类继承
C++支持三种不同的继承方式:private、protected和public,继承方式只影响派生类外部对基类成员的访问权限,而不影响派生类在内部对基类成员的访问权限。私有继承意味着所有基类成员将被继承为派生类的私有成员;保护继承意味着基类所有public成员被继承为protected,其它成员不受影响;公有继承则保持基类成员的原有访问控制不变。例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| class Base { private: int _ID; protected: char* _Name; public: void show(){cout<<_ID<<": "<<_Name;} }
class Child1: private Base { private: void test() { name=""; show(); } }
class Child2: protected Base { private: void test() { name=""; show(); } }
class Child3: public Base { private: void test() { name=""; show(); } }
class CChild1: public Child1 { private: void test() { name=""; show(); } }
class CChild2: public Child2 { private: void test() { name=""; show(); } }
Child1 c1; Child2 c2; c1.show(); c2.show();
|
C++中的方法重写
解释方法重写前需要弄明白函数重载与方法重写的概念。函数重载发生在同一类作用域,而方法重写发生在类继承中,即使子类用不同的参数列表重写父类方法,他也不是重载,而是重写,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class Base { public: void show(){cout<<"base";} }
class Child: public Base { public: void show(int i){cout<<"child";} }
Child c; c.show(); c.show(0);
|
发生重写时,函数的父类版本将被子类隐藏。
派生类重写基类虚方法时,要求子类保持方法签名一致,否则将变成上面的普通方法重写,子类将隐藏父类虚方法。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| class Base { public: virtual void show() {cout<<"base";} }
class Child: public Base { public: void show(int i) {cout<<"child";} }
class Child1: public Base { public: void show(int i) {cout<<"child1";} void show() {cout<<"child1 virtual";} } Child c; c.show(); Child1 c1; c1.show(); c1.show(0);
|
.NET中的函数重写
当子类保持函数签名一致时,对于普通方法重写,需要显式指定new(Shadows)关键字;对于虚方法,需要显式指定override关键字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| class BaseCls { public virtual void show() { Console.WriteLine("Base"); } }
class ChildCls:BaseCls { public override void show() { Console.WriteLine("Child"); } }
class BadChildCls:BaseCls { public new void show() { Console.WriteLine("BadChild"); } }
BaseCls a,b; a=new ChildCls(); b=new BadChildCls(); a.show(); b.show();
|
当子类方法与父类函数签名不一致时,.NET将其视为重写+重载,而不是像C++一样简单的隐藏父类方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| //VB.NET Class BaseCls Public Overridable Sub Show() Console.WriteLine("base") End Sub End Class
Class Child:Inherits BaseCls Public Overloads Sub Show(Byval i as Int32) Console.WriteLine("child") End Sub End Class
Dim c as New Child c.Show(0) //OK c.Show() //OK
//C# class BaseCls { public virtual void Show() {Console.WriteLine("base");} }
class Child: BaseCls { public void Show(int i) {Console.WriteLine("child");} }
Child c = new Child(); c.Show(); //OK c.Show(0); //OK
|
上述代码实际上可以拆分为:
1 2 3 4 5 6 7 8 9 10 11
| Class Child:Inherits BaseCls //方法重写 Public Overrides Sub Show() MyBase.Show() End Sub //函数重载 Public Overloads Sub Show(Byval i as Int32) Console.WriteLine("child") End Sub End Class
|
不过两者略有区别,通过查看生成的IL代码,第一种写法中Child只有Show(Int32)方法,对Show()的调用直接编译为MyBase.Show(),但使用反射仍然可以获取Child.Show()方法。