C++黑马程序员——P131-134. 继承 同名(静态)成员处理,多继承,菱形继承,虚继承
- P131. 类和对象——继承——同名成员处理
- P132. 类和对象——继承——同名静态成员处理
- P133. 类和对象——继承——继承语法
- P134. 类和对象——继承——菱形继承问题以及解决方法
- P131. 同名成员处理
问题:当子类与父类出现同名的成员,如何通过子类对象,访问到子类或父类中同名的数据呢?
● 访问子类同名成员 直接访问即可
● 访问父类同名成员 需要加作用域
1 //继承中同名成员处理
2 class Base
3 {
4 public:
5 Base()
6 {
7 m_A = 100;
8 }
9
10 void func()
11 {
12 cout << "Base 的func() 函数调用" << endl;
13 }
14
15 void func(int a)
16 {
17 cout << "Base 的func(int a) 函数调用" << endl;
18 }
19 int m_A;
20 };
21
22 class Son :public Base
23 {
24 public:
25 Son()
26 {
27 m_A = 200;
28 }
29
30 void func()
31 {
32 cout << "Son 的func() 函数调用" << endl;
33 }
34 int m_A;
35 };
36
37 void test01()
38 {
39 Son s1;
40 cout << "s1.m_A = " << s1.m_A << endl; //200
41 //如果通过子类对象访问父类同名成员,需要加作用域
42 cout << "Base 下m_A = " << s1.Base::m_A << endl;
43 }
44
45 //同名成员函数处理方式
46 void test02()
47 {
48 Son s2;
49 s2.func();
50 s2.Base::func();
51 //如果子类出现和父类同名的成员函数,子类的同名成员会隐藏掉父类中所有同名成员函数
52 //如果想访问到父类中被隐藏的同名成员函数,需要加作用域
53 s2.Base::func(10); //这一行,如果不加 Base:: 就会报错
54 }
55
56 int main()
57 {
58 test01();
59 test02();
60 return 0;
61 }
运行结果:
- P132. 同名静态成员处理
问题:继承中同名的静态成员在子类对象上如何进行访问?
静态成员 和 非静态成员出现同名,处理方式一致
● 访问子类同名成员 直接访问即可
● 访问父类同名成员 需要加作用域
1 //继承中同名静态成员的处理方式
2 class Base
3 {
4 public:
5 static void func()
6 {
7 cout << "Base的static void func()调用" << endl;
8 }
9 static void func(int a)
10 {
11 cout << "Base的static void func(int a)调用" << endl;
12 }
13 static int m_A;
14 };
15 int Base::m_A = 100;
16
17 class Son:public Base
18 {
19 public:
20 static void func()
21 {
22 cout << "Son的static void func()调用" << endl;
23 }
24 static int m_A;
25 };
26 int Son::m_A = 200;
27
28 //同名静态成员属性
29 void test01()
30 {
31 //1. 通过对象访问
32 cout << "通过对象访问:" << endl;
33 Son s1;
34 cout << "s1.m_A = " << s1.m_A << endl;
35 cout << "s1.Base::m_A = " << s1.Base::m_A << endl;
36 //2. 通过类名访问
37 cout << "通过类名访问:" << endl;
38 cout << "Son::m_A = " << Son::m_A << endl;
39 cout << "Son::Base::m_A = " << Son::Base::m_A << endl; //第一个::代表通过类名方式访问 第二个::代表访问父类作用域下
40 }
41 //同名静态成员函数
42 void test02()
43 {
44 //1. 通过对象访问
45 cout << "通过对象访问:" << endl;
46 Son s2;
47 s2.func();
48 s2.Base::func();
49 //2. 通过类名访问
50 cout << "通过类名访问:" << endl;
51 Son::func();
52 Son::Base::func();
53 //子类出现和父类同名静态成员函数,也会隐藏父类中所有同名成员函数
54 //如果想访问父类中被隐藏的同名成员,需要加作用域
55 Son::Base::func(100); //不加 Base:: 会报错
56 }
57
58
59 int main()
60 {
61 test01();
62 cout << endl;
63 test02();
64 return 0;
65 }
运行结果:
总结:同名静态成员处理方式和非静态处理方式一样,只不过有两种访问的方式(通过对象 和 通过类名)
- P133. 继承语法
多继承语法
C++允许一个类继承多个类
语法:class 子类:继承方式 父类1,继承方式 父类2...
多继承可能会引发父类中有同名成员出现,需要加作用域区分
C++实际开发中不建议用多继承
1 //多继承语法
2 class Base1
3 {
4 public:
5 Base1()
6 {
7 m_A = 1;
8 }
9 int m_A;
10 };
11
12 class Base2
13 {
14 public:
15 Base2()
16 {
17 m_A = 2;
18 }
19 int m_A;
20 };
21
22 //子类,继承 Base1 和 Base2
23 class Son :public Base1, public Base2
24 {
25 public:
26 Son()
27 {
28 m_C = 3;
29 m_D = 4;
30 }
31 int m_C;
32 int m_D;
33 };
34
35 void test01()
36 {
37 Son s1;
38 //当父类中出现同名成员,需要加作用域区分
39 cout << "s1.Base1::m_A = " << s1.Base1::m_A << endl;
40 cout << "s1.Base2::m_A = " << s1.Base2::m_A << endl;
41 }
42
43 int main()
44 {
45 test01();
46 return 0;
47 }
运行结果:
- P134. 菱形继承问题以及解决方法
菱形继承概念:
● 两个派生类继承同一个基类
● 又有某个类同时继承着两个派生类
● 这种继承被称为菱形继承,或者钻石继承
菱形继承问题:
1. 羊继承了动物的数据,驼同样继承了动物的数据,当草泥马使用数据时,就会产生二义性。
2. 草泥马继承自 动物 的数据继承了两份,其实我们应该清楚,这份数据我们只需要一份就可以(比如 有一份数据代表 动物年龄,草泥马只需要继承一份就可以)。
1 //动物类
2 class Animal
3 {
4 public:
5 int m_Age;
6 };
7
8 //羊类
9 class Sheep : public Animal
10 {};
11 //驼类
12 class Camel : public Animal
13 {};
14 //草泥马类
15 class Alpaca :public Sheep, public Camel
16 {};
17
18 void test01()
19 {
20 Alpaca a1;
21 //a1.m_Age = 18; //报错
22 //当菱形继承,两个父类拥有相同成员,需要加作用域区分
23 a1.Sheep::m_Age = 18;
24 a1.Camel::m_Age = 28;
25 cout << "a1.Sheep::m_Age = " << a1.Sheep::m_Age << endl;
26 cout << "a1.Camel::m_Age = " << a1.Camel::m_Age << endl;
27 //m_Age这份数据,只要有一份就可以,菱形继承导致数据有两份,资源浪费
28
29 }
30
31 int main()
32 {
33 test01();
34 return 0;
35 }
运行结果:
解决办法:虚继承
1 //动物类
2 class Animal
3 {
4 public:
5 int m_Age;
6 };
7
8 //利用虚继承,可以解决菱形继承的问题
9 //继承方式之前,加上关键字virtual,变为虚继承
10 //被虚继承的 Animal 类,称为虚基类
11 //羊类
12 class Sheep :virtual public Animal
13 {};
14 //驼类
15 class Camel :virtual public Animal
16 {};
17 //草泥马类
18 class Alpaca :public Sheep, public Camel
19 {};
20
21 void test01()
22 {
23 Alpaca a1; //当菱形继承,两个父类拥有相同成员,需要加作用域区分
26 a1.Sheep::m_Age = 18;
27 a1.Camel::m_Age = 28;
28 cout << "a1.Sheep::m_Age = " << a1.Sheep::m_Age << endl;
29 cout << "a1.Camel::m_Age = " << a1.Camel::m_Age << endl;
30
31 cout << "a1.m_Age = " << a1.m_Age << endl; //此时可以直接访问到 a1.m_Age 了
32 }
33
34 int main()
35 {
36 test01();
37 return 0;
38 }
运行结果:
vbptr:虚 基类 指针
v——virtual
b——base
ptr——pointer
vbptr 指向 vbtable(虚 基类 表),表中记录了一个偏移量,vbptr+偏移量 就是唯一继承的 m_Age 的地址
总结:
● 菱形继承带来的主要问题是子类继承两份相同的数据,导致资源浪费以及毫无意义
● 利用虚继承可以解决菱形继承问题
(〃>_<;〃)(〃>_<;〃)(〃>_<;〃)