面向对象中的继承, 虚方法, 抽象类,抽象函数,接口等概念
面向对象继承中的构造函数问题:
在继承的前提下,会先执行父类的构造函数,默认执行无参构造函数。
因为在子类中是需要一个父类的对象,这样才可以继承到父类的属性方法等,在子类中可以使用base访问父类的内容
如果父类没有无参的构造函数,可以手动执行父类的构造函数。语法base(参数列表)执行父类的构造函数
先创建父类的对象在创建子类的对象:
先创建父类 , 因为子类需要继承父类的内容,有base执行父类所以先创建父类
析构函数是先执行父类的还是子类的:
先销毁子类,因为子类中有base指向父类的地址,所以在销毁子类的时候相当继承链的父类也会被gc销毁,因为gc销毁的原理是没有引用的时候才会被销毁,所以先销毁子类,因为子类销毁了,父类就没有引用了,父类就会被gc销毁。
虚方法:
作用:用与被子类重写,使用多态,实现多态的一种手段
关键字: virtual
重写父类虚方法关键字:override,可以被重写也可以不被重写
使用虚函数实现上边不同等级员工发工资的例子:
公司有不同的人,员工有不能的等级,普通员工工资是3000,p2工资是5000,p3工资8000,如何使用面向对象的思想去实现
父类:
public class People { public int Age { get; set; } public string Name { get; set; } //发工资的虚方法 public virtual void Salary() { Console.WriteLine("发工资3000"); } }
三个子类:
//普通员工 public class Normal : People { /// <summary> /// 重写父类的方法 /// </summary> //public override void Salary() //{ // Console.WriteLine("发工资3000"); //} } //中级员工 class P2:People { /// <summary> /// 重写父类的方法 /// </summary> public override void Salary() { Console.WriteLine("发工资5000"); } } //高级员工 class P3 : People { /// <summary> /// 重写父类的方法 /// </summary> public override void Salary() { Console.WriteLine("发工资8000"); } }
使用:
static void Main(string[] args) { People people = new Normal(); people.Salary(); People people2 = new P2(); people2.Salary(); people = new P3(); people.Salary(); Console.ReadLine(); }
效果如下:
有虚方法,有没有虚属性,或者有没有虚索引?
有虚属性,因为属性本身其实是两个方法,也有虚索引,因为索引是一种特殊的属性,本质也是方法
抽象类与抽象函数
抽象类的作用:为了被子类继承,从而实现多态。是一种约定,约定必须要具体那些方法。
抽象函数作用:都是为了被子类重写,重写实现多态(同一个对象同一个方法,指向不同从而实现多态)
抽象函数特点:不能有方法体,子类必须重写
关键字:abstract
虚函数和抽象函数的异同点:
相同点: 都可以被子类重写从而实现多态
不同点:
1:虚函数有方法体,抽象函数没有方法体。也就是说虚函数可以有默认实现,抽象函数不行
2:虚函数可以被重写,也可以不被重写,抽象函数必须被重写
3:抽象方法只能在抽象类中,抽象方法不能在普通类中
抽象类和普通类的异同点:
相同点:都可以被继承,也可以继承其他类,都可以有普通方法
不同点:
1:普通类可以被实例化,抽象类不行,抽象类提供一种约定一种类的模板,不能被实例化,因为实例化是没有意义,具体的类有实现才有意义
2:抽象类才能有抽象方法,普通类不行
使用抽象类实现不同图形的面积计算
父类:
/// <summary> /// 抽象类 /// </summary> public abstract class Shape { public abstract int length { get; set; } public string type { get; set; } /// <summary> /// 抽象方法 /// </summary> public abstract void Area(int r); }
两个子类:
public class Circle : Shape { public const double pi = 3.14; /// <summary> /// 重写方法,实现方法 /// </summary> public override void Area(int r) { Console.WriteLine("圆形面积:"+(pi * r * r)); } public override int length { get { return length; } set { length = value; } } } public class Rectangle : Shape { public override void Area(int r) { Console.WriteLine("矩形面积:"+(r * r)); } public override int length { get { return length; } set { length = value; } } }
使用:
class Program { static void Main(string[] args) { Shape shape = new Circle(); shape.Area(6); shape = new Rectangle(); shape.Area(6); Console.ReadLine(); } }
效果如下:
有没有抽象属性?
可以有抽象属性,用法和虚属性类似,不同点:虚属性可以有自己的实现,抽象属性不行
接口(在低版本中不能有方法体,在高版本中接口也可以有方法体,我们这里讨论低版本中)
和抽象类非常类似:都是一种约定,约定必须要具备的功能,接口里边的方法都是抽象的,不能有方法体。接口里边的方法默认都是公共的,默认都是抽象的,所以定义的时候只需要定义返回值方法名参数,public和abstract会自动加上
接口和抽象类的异同点:
相同点:都是一种约定,约定必须要具备的功能
不同点:
1:接口里边不能有普通方法,但是抽象类可以
2:重写接口的方法不需要加override,但是重写抽象函数必须要加
3:接口可以多重继承,但是抽象类不行
使用接口的方式来实现不同类型图形的面积计算
public interface IShape { void Area(int r); int length { get; } int this[int index] { get; } } //矩形类 public class Renctangle : IShape { public void Area(int r) { Console.WriteLine("矩形面积" + r * r); } public int length { get { return length; } } public int this[int index] { get { return 1; } } } //圆形类 public class Circle : IShape { public void Area(int r) { Console.WriteLine("圆形面积:" + 3.14 * r * r); } public int length { get { return length; } } public int this[int index] { get { return 1; } } }
效果和用法和上面一样