类的继承与派生(virtual、override)

mac2024-05-29  54

C#中类的继承与派生在性质上类似C++,但在有些方面有一些区别。

C#中所有类都派生自object类

除了特殊的类object,所有的类都是派生类,即使他们没有基类规格说明,类object是唯一的非派生类,因为他是继承层次结构的基础,与C++不同(C++中允许多继承),在C#中一个类声明的基类规格说明中只能有一个单独的类,也就是只允许单继承,虽然类只能直接继承一个基类,但继承的层次没有限制。在写法上也与C++不同,C#中不存在公有继承、私有继承等这些继承方式,所以在写的时候冒号后面直接接上基类的名字即可,例如 class A : B

屏蔽基类成员

虽然子类不能删除它继承的任何成员,但可以用与父类成员名称相同的成员来屏蔽(mask)父类成员,这是继承的主要功能之一。

屏蔽的使用: (1)屏蔽一个继承的数据成员,需要声明一个新的相同类型的成员,并使用相同名称 (2)屏蔽一个继承的函数成员,需要声明一个带有相同签名的函数成员,签名由名称和参数列表组成,不包括返回类型 (3)要让编译器知道你在故意屏蔽继承的成员,可以使用new修饰符,否则,程序可以成功编译,但编译器会警告你隐藏了一个继承的成员 (4)也可以屏蔽静态成员

class A { public int i; public void foo(){ } } class B :A { new public int i; public void foo() { } //不加new会有一个警告 }

基类访问

表达式:base.成员

虚方法(virtual)和覆写方法(override)

类似C++中的多态的产生,C++中使用子类对象给父类指针赋值,当该父类指针调用虚函数时,就会产生多态,同理C#中使用子类对象的栈上引用给父类引用赋值,当父类引用调用虚方法时,就会产生多态。

class A { public virtual void foo() { Console.WriteLine("父类"); } } class B :A { public override void foo() { Console.WriteLine("子类"); } } class Program { static void Main(string[] args) { B b = new B(); A a = (A)b; a.foo(); //输出子类 } }

virtual和override修饰符的使用

父类中被覆写的方法用virtual来修饰,子类中覆写后的方法需要用override来修饰

(1)覆写和被覆写的方法必须有相同的可访问性 (2)不能覆写static方法或非虚方法 (3)方法、属性、索引器以及事件,都可以被声明为virtual和override

virtual与override的内部调用机制

当使用对象基类部分的引用调用一个覆写的方法时,方法的调用被沿派生层次上溯执行,取寻找标记为override的方法,如果在更高的派生级别有该方法的其他声明,但没有被标记为override,那么它们不会被调用

class A { public virtual void foo() { Console.WriteLine("A"); } } class B :A { public override void foo() { Console.WriteLine("B"); } } class C:B { public override void foo() { Console.WriteLine("C"); } } class Program { static void Main(string[] args) { C c = new C(); A a = (A)c; a.foo(); //输出C } }

此时a调用foo函数,会根据继承关系向上寻找override方法,在C中有此方法则会调用到C中的foo所以打印出C

class C:B { public new void foo() { Console.WriteLine("C"); } } class Program { static void Main(string[] args) { C c = new C(); A a = (A)c; a.foo(); //输出B } }

如果将C中的foo函数使用new来修饰,而不是override,则在调用时找不到C中的override修饰的foo函数,则只能调用B中被override修饰的foo函数所以输出为B

 

最新回复(0)