C++中的虚基类

简介: 🐰虚基类🌸虚基类的声明🌸虚基类的初始化🌸总结

🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀

目录

🐰虚基类

🌸虚基类的声明

🌸虚基类的初始化

🌸总结


🐰虚基类

如果一个派生类有多个直接基类,而这些直接基类又有一个共同的基类,则在最终的派生类中会保留该间接共同基类成员的多份同名成员。这种情况有时也是有可能出现的,还增加了访问这些成员时的困难,容易出错。为了解决这个问题,可以使用虚基类的方法。

例如:

1. class Wood
2. {
3.     ...
4. };
5. class Sofa:virtual public Wood
6. {
7.     ...
8. };
9. class Bed:virtual public Wood
10. {
11.     ...
12. };

注意:虚基类并不是在声明基类时声明的,而是在声明派生类时的指定继承方式时声明的。因为一个基类可以在派生一个派生类时作为虚基类,而在派生另一个派生类时不作虚基类。

🌸虚基类的声明

声明虚基类的形式:

class 派生类名:virtual 继承方式 基类名

就是在声名派生类时,将关键字virtual加在继承方式的前面

注意:虚基类这种方法方法只影响从指定了虚基类的派生类中进一步派生出的类,它不会影响派生类本身。为了保证虚基类在派生类中只继承一次,应当在该基类的所有直接派生类中都把基类声明为虚基类。

🌸虚基类的初始化

如果虚基类中定义了带参数的构造函数,而且没有定义默认的构造函数,则在其所有的派生类(包括直接派生和间接派生的派生类)中,都要通过构造函数的初始化列表进行初始化。

虚基类的初始化。

例如:

person的数据成员有name, age,sex,add,phone,person派生了两个派生类Teaher和Cadre,Teacher新增了一个受保护的数据成员position,Cadre新增了一个受保护的数据成员post,类 TeacherCadre公有继承了Teaher和Cadre,由于Teaher和Cadre公有继承了person,有同名的成员,所以这里我们需要使用虚基类来处理,处理方法如下

1. #include<iostream>
2. using namespace std;
3. class person
4. {
5. public:
6. person(string Name,int Age,string Sex,string Add,string Phone)
7.     {
8.         name=Name;
9.         age=Age;
10.         sex=Sex;
11.         add=Add;
12.         phone=Phone;
13.     }
14. public:
15.     string name;
16. int age;
17.     string sex;
18.     string add;
19.     string phone;
20. };
21. class Teacher:virtual public person//虚基类
22. {
23. public:
24. Teacher(string name,int age,string sex,string add,string phone,string Position):person(name,age,sex,add,phone)
25.     {
26.         position=Position;
27.     }
28. void display()
29.     {
30.         cout<<"         姓名:"<<name<<endl;
31.         cout<<"         年龄:"<<age<<endl;
32.         cout<<"         地址:"<<add<<endl;
33.         cout<<"         电话:"<<phone<<endl;
34.     }
35. protected:
36.     string position;
37. };
38. class Cadre:virtual public person//虚基类
39. {
40. public:
41. Cadre(string name,int age,string sex,string add,string phone,string Post):person(name,age,sex,add,phone)
42.     {
43.         post=Post;
44.     }
45. protected:
46.     string post;
47. };
48. class TeacherCadre:public Teacher,public Cadre
49. {
50. public:
51. TeacherCadre(string name,int age,string sex,string add,string phone,string Position,string Post,double Wage):person(name,age,sex,add,phone),Teacher(name,age,sex,add,phone,Position),Cadre(name,age,sex,add,phone,Post)
52.                  {
53.                      wage=Wage;
54.                  }
55. void show()
56.     {
57.         Teacher::display();
58.         cout<<"         职务:"<<post<<endl;
59.         cout<<"         工资:"<<wage<<endl;
60.     }
61. protected:
62. double wage;
63. };
64. int main()
65. {
66. TeacherCadre t1("张三",32,"男","北京","1878****454","教导主任","老师",7856.34);
67.     t1.show();
68. }
69. 结果:
70. 姓名:张三
71. 年龄:32
72. 地址:北京
73. 电话:1878****454
74. 职务:老师
75. 工资:7856.34

或许大家会有疑问:类TeacherCadre的构造函数通过初始化列表调用了基类(person)的构造函数,而类Teacher和Cadre的构造函数也通过初始化列表调用了虚基类(person)的构造函数,这样虚基类的构造函数岂不是被调用了3次?大家不必担心,C++编译系统只执行最后的派生类对虚基类的构造函数的调用,而忽略其他派生类(Teacher和Cadre)对虚基类的构造函数的调用,这就保证了虚基类的数据成员不会被多次初始化。

例如:我们把虚基类的构造函数改为

1. person(string Name,int Age,string Sex,string Add,string Phone)
2.     {
3.         name=Name;
4.         age=Age;
5.         sex=Sex;
6.         add=Add;
7.         phone=Phone;
8.         cout<<"秋水共长天一色,落霞与孤鹜齐飞"<<endl;
9.     }
10. 看一下运行结果:
11. 秋水共长天一色,落霞与孤鹜齐飞
12.          姓名:张三
13.          年龄:32
14.          地址:北京
15.          电话:1878****454
16.          职务:老师
17.          工资:7856.34

所以虚基类的构造函数真的只调用了一次,那就是最后一个的派生类调用了虚基类的构造函数

🌸总结

派生类构造函数调用的次序有如下的3个原则

(1)同一层中对虚基类构造函数的调用优先于对非基类构造函数的调用

(2)若同一层次中包含多个虚基类,则这些虚基类的构造函数按照它们在继承方式中的声明次序调用。

(3)若虚基类由非基类派生出来,则仍然调用基类的构造函数,在按派生类中构造函数的执行顺序调用

派生类的析构函数调用次序与构造函数恰恰相反。

最后一点,使用继承的时候一定注意二义性的问题,其实能够用单继承解决的就用单继承,因为多继承容易出问题。在面向对向对象的程序设计语言中java,Smalltalk并不支持多继承。

🌸🌸🌸如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家! 🌸🌸🌸  

相关文章
|
2天前
|
编译器 C++
C++ 类构造函数初始化列表
构造函数初始化列表以一个冒号开始,接着是以逗号分隔的数据成员列表,每个数据成员后面跟一个放在括号中的初始化式。
42 30
|
16天前
|
存储 编译器 C++
C ++初阶:类和对象(中)
C ++初阶:类和对象(中)
|
1月前
|
存储 安全 编译器
【C++】类和对象(下)
【C++】类和对象(下)
【C++】类和对象(下)
|
16天前
|
C++
C++(十六)类之间转化
在C++中,类之间的转换可以通过转换构造函数和操作符函数实现。转换构造函数是一种单参数构造函数,用于将其他类型转换为本类类型。为了防止不必要的隐式转换,可以使用`explicit`关键字来禁止这种自动转换。此外,还可以通过定义`operator`函数来进行类型转换,该函数无参数且无返回值。下面展示了如何使用这两种方式实现自定义类型的相互转换,并通过示例代码说明了`explicit`关键字的作用。
|
16天前
|
存储 设计模式 编译器
C++(十三) 类的扩展
本文详细介绍了C++中类的各种扩展特性,包括类成员存储、`sizeof`操作符的应用、类成员函数的存储方式及其背后的`this`指针机制。此外,还探讨了`const`修饰符在成员变量和函数中的作用,以及如何通过`static`关键字实现类中的资源共享。文章还介绍了单例模式的设计思路,并讨论了指向类成员(数据成员和函数成员)的指针的使用方法。最后,还讲解了指向静态成员的指针的相关概念和应用示例。通过这些内容,帮助读者更好地理解和掌握C++面向对象编程的核心概念和技术细节。
|
30天前
|
存储 算法 编译器
c++--类(上)
c++--类(上)
|
1月前
|
编译器 C++
virtual类的使用方法问题之C++类中的非静态数据成员是进行内存对齐的如何解决
virtual类的使用方法问题之C++类中的非静态数据成员是进行内存对齐的如何解决
|
1月前
|
编译器 C++
virtual类的使用方法问题之静态和非静态函数成员在C++对象模型中存放如何解决
virtual类的使用方法问题之静态和非静态函数成员在C++对象模型中存放如何解决
|
1月前
|
编译器 C++
virtual类的使用方法问题之在C++中获取对象的vptr(虚拟表指针)如何解决
virtual类的使用方法问题之在C++中获取对象的vptr(虚拟表指针)如何解决
|
1月前
|
编译器 C++
【C++】类和对象(中)
【C++】类和对象(中)