类继承

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:
//内部访问权限不受影响,可访问基类protected和public成员
void test()
{
name=""; //protected Base::name
show(); //public Base::show()
}
}

//保护继承同上
class Child2: protected Base
{
private:
void test()
{
name="";
show();
}
}

class Child3: public Base
{
private:
void test()
{
name="";
show();
}
}

//Child1已将基类成员继承为private,CChild1显然不可访问
class CChild1: public Child1
{
private:
void test()
{
name=""; //不可访问:private Child1::name
show(); //不可访问:private Child1::show()
}
}

//Child2是保护继承,基类非private成员均被继承为protected,CChild2显然可以访问
class CChild2: public Child2
{
private:
void test()
{
name=""; //OK:protected Child2::name
show(); //OK:protected Child2::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(); //Error
c.show(0); //OK

发生重写时,函数的父类版本将被子类隐藏。

派生类重写基类虚方法时,要求子类保持方法签名一致,否则将变成上面的普通方法重写,子类将隐藏父类虚方法。例如:

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";}
}

//签名不一致,隐藏父类show()方法
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(); //Error.
Child1 c1;
c1.show(); //OK.调用Child1::show()
c1.show(0); //OK.调用Child1::show(int)

.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");
}
}

//虚方法重写(省略override则默认为new)
class ChildCls:BaseCls
{
public override void show()
{
Console.WriteLine("Child");
}
}

//普通重写(new可省略)
class BadChildCls:BaseCls
{
public new void show()
{
Console.WriteLine("BadChild");
}
}

BaseCls a,b;
a=new ChildCls();
b=new BadChildCls();
a.show();
b.show();

/*输出:
Child
Base
*/

当子类方法与父类函数签名不一致时,.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()方法。

 评论




载入天数...载入时分秒...  |  总访问量为
Powered by Github and MarkdownPad 2

--------------------------- 别拉了,我是有底线的>_< ---------------------------