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 的地址

 

总结:

● 菱形继承带来的主要问题是子类继承两份相同的数据,导致资源浪费以及毫无意义

● 利用虚继承可以解决菱形继承问题

(〃>_<;〃)(〃>_<;〃)(〃>_<;〃)

posted @ 2023-02-23 22:49  我会变强的  阅读(37)  评论(0编辑  收藏  举报