继承
通过继承,可以定义一个新类,新类纳入一个已经声明的类并扩展。
1.类总是派生自System.object或者用户选择的一个类,类可以派生自多个接口。
2.结构总是派生自System.ValueType,结构可以派生自多个接口。
3.对于接口,可以多重继承接口,也可以多层继承接口。
4.已存在的类称为基类;新类成为派生类,派生类包括了自己类声明的成员和基类的成员。
使用基类的引用
1.派生类的实例由基类的实例加上派生类附加的成员组成。可以通过派生类对象的引用,使用类型转换运算符把该引用转换为基类类型。
2.使用基类的引用时,只能访问基类成员,不能看到派生类的对象。
3.通过使用基类的虚方法和派生类的覆写方法可以使基类的引用访问派生类对应的成员对象。
- 虚方法
把一个基类方法声明为virtua,就可以在任何派生类中重写该方法。
在C#中,函数在默认情况下不是虚拟的,但(构造函数除外)可以显示声明为virtual。
重写方法需要在派生类中使用override关键字显示声明。同时,重写方法的签名、可访问性和返回类型必须完全匹配。否则就不能覆盖基类成员。
成员字段和静态函数不能声明为virtual,虚方法只对类中实例函数成员有意义。
方法、属性、索引和事件,都可以被声明为virtual和override。
class Program
{
private static void Main()
{
BaseClass baseClass = new BaseClass();
baseClass.GetArea(2, 4);
BaseClass derivedClass = new DerivedClass();
derivedClass.GetArea(2, 4);
}
}
/// <summary>
/// 基类
/// </summary>
class BaseClass
{
//虚属性
public virtual int Area { get; set; }
//虚方法
public virtual void GetArea(int width, int height) => Console.WriteLine(width * height);
}
/// <summary>
/// 派生类
/// </summary>
class DerivedClass: BaseClass
{
//重写基类的虚属性
public override int Area => 100;
//重写基类的虚方法
public override void GetArea(int width, int height) => Console.WriteLine(width * height * height);
}
2.隐藏基类成员
1.派生类不能删除继承基类的任何成员,但是可以隐藏基类成员。
2.通过在派生类中声明(new修饰符)新的带有相同签名的函数成员,可以隐藏或者掩盖继承的函数成员。
3.可以隐藏静态成员。
4.如果签名相同的方法在基类和派生类中都进行了声明,但该方法没有声明为虚方法和重写,派生类方法就会隐藏基类方法。
即在派生类中无法访问到基类的该隐藏的方法。
class Program
{
private static void Main()
{
BaseClass baseClass = new DerivedClass();
baseClass.GetArea(2, 4);
DerivedClass derivedClass = new DerivedClass();
derivedClass.GetArea(2, 4);
}
}
/// <summary>
/// 基类
/// </summary>
class BaseClass
{
//虚属性
public virtual int Area { get; set; }
//虚方法
public void GetArea(int width, int height) => Console.WriteLine(width * height);
}
/// <summary>
/// 派生类
/// </summary>
class DerivedClass: BaseClass
{
//重写基类的虚属性
public override int Area => 100;
//隐藏基类的GetArea方法,使之在派生类中无法调用基类的GetArea方法
public new void GetArea(int width, int height) => Console.WriteLine(width * height * height);
}
3.基类访问
1.如果派生类必须访问被隐藏的基类成员,则需要使用积累访问表达式(base.成员名称)。
2.不建议使用隐藏基类成员和基类访问方式设计。
4.抽象类和抽象方法
抽象类不能实例化,而抽象方法不能直接实现,必须在非抽象性的派生类中重写。如果类包含抽象方法,则该类也是抽象的,也必须声明为抽象的。抽象类和抽象成员必须使用abstract修饰符。
抽象类
抽象类是设计用来被继承的。抽象类只能被用作其他类的基类。
不能创建抽象类的实例。
抽象类可以包含抽象成员或非抽象成员。抽象类的成员可以是抽象成员和普通带实现的成员的任意组合。
抽象类自己可以派生自另一个抽象类。
任何派生自抽象类的类必须使用override关键字实现该类所有的抽象成员,除非派生类自己也是抽象类。
抽象成员
抽象成员是设计用来被覆写的函数成员。
抽象成员没有实现代码块。抽象成员的代码块用分号表示。
从抽象基类中派生类型时,需要实现所有抽象成员。
虚成员 抽象成员
关键字 virtual abstract
实现体 有实现体 没有实现体,被分号替代
派生类 能被覆写 必须被覆写
成员类型 方法 属性 事件 索引
class Program
{
private static void Main()
{
//抽象类只能实例化,只能实例化派生类
BaseClass baseClass = new DerivedClass2();
baseClass.GetArea(2, 4);
DerivedClass2 derivedClass = new DerivedClass2();
derivedClass.GetArea(2, 4);
}
}
/// <summary>
/// 抽象基类
/// </summary>
abstract class BaseClass
{
//抽象属性
public abstract int Area { get;}
//抽象方法
public abstract void GetArea(int width, int height);//=> Console.WriteLine(width * height);
}
/// <summary>
/// 抽象派生类
/// </summary>
abstract class DerivedClass: BaseClass
{
//实现基类的抽象属性
public override int Area => 100;
//实现基类的抽象方法
public override void GetArea(int width, int height) => Console.WriteLine(width * height * height);
//抽象方法 在派生基类的基础上,定义自己类的抽象方法
public abstract void GetArea2(int width, int height);
}
/// <summary>
/// 派生类
/// </summary>
class DerivedClass2 : DerivedClass
{
//实现基类的抽象属性
public override int Area => 100;
//实现基类的抽象方法
public override void GetArea(int width, int height) => Console.WriteLine(width * height * height);
//实现基类的抽象方法
public override void GetArea2(int width, int height) => Console.WriteLine(width * height * height);
}
5.密封类和密封方法
如果一个类不允许被继承,那么就需要使用sealed修饰符进行声明。密封类只能被用作独立的类,不能用作基类。密封一个方法,则说明该方法不能被重写。
密封类和密封方法可以保证不被继承和改写,同时密封类可以提高性能。
要在方法或属性使用sealed关键字,必须先从基类把它声明为virtual。
class Program
{
private static void Main()
{
//抽象类只能实例化,只能实例化派生类
BaseClass baseClass = new DerivedClass2();
baseClass.GetArea(2, 4);
DerivedClass2 derivedClass = new DerivedClass2();
derivedClass.GetArea(2, 4);
}
}
/// <summary>
/// 抽象基类
/// </summary>
abstract class BaseClass
{
//抽象属性
public abstract int Area { get;}
//抽象方法
public abstract void GetArea(int width, int height);//=> Console.WriteLine(width * height);
}
/// <summary>
/// 抽象派生类
/// </summary>
abstract class DerivedClass: BaseClass
{
//实现基类的抽象属性
public override int Area => 100;
//实现基类的抽象方法,并且使之称为密封方法
public sealed override void GetArea(int width, int height) => Console.WriteLine(width * height * height);
//抽象方法 在派生基类的基础上,定义自己类的抽象方法
public abstract void GetArea2(int width, int height);
}
/// <summary>
/// 密封派生类
/// </summary>
sealed class DerivedClass2 : DerivedClass
{
//实现基类的抽象属性
public override int Area => 100;
//基类的方法声明为密封方法,所以派生类不能重写该方法
//public override void GetArea(int width, int height) => Console.WriteLine(width * height * height);
//实现基类的抽象方法
public override void GetArea2(int width, int height) => Console.WriteLine(width * height * height);
}