🐶博主主页:@ᰔᩚ. 一怀明月ꦿ 

❤️‍🔥专栏系列:线性代数,C初学者入门训练,题解C,C的使用文章,「初学」C++

🔥座右铭:“不要等到什么都没有了,才下定决心去做”

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

目录

🐰虚基类

🌸虚基类的声明

🌸虚基类的初始化

🌸总结


🐰虚基类

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

例如:

class Wood
{
    ...
};
class Sofa:virtual public Wood
{
    ...
};
class Bed:virtual public Wood
{
    ...
};
注意:虚基类并不是在声明基类时声明的,而是在声明派生类时的指定继承方式时声明的。因为一个基类可以在派生一个派生类时作为虚基类,而在派生另一个派生类时不作虚基类。

🌸虚基类的声明

声明虚基类的形式:
class 派生类名:virtual 继承方式 基类名

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

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

🌸虚基类的初始化

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

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

#include<iostream>
using namespace std;
class person
{
public:
    person(string Name,int Age,string Sex,string Add,string Phone)
    {
        name=Name;
        age=Age;
        sex=Sex;
        add=Add;
        phone=Phone;
    }
public:
    string name;
    int age;
    string sex;
    string add;
    string phone;
};
class Teacher:virtual public person//虚基类
{
public:
    Teacher(string name,int age,string sex,string add,string phone,string Position):person(name,age,sex,add,phone)
    {
        position=Position;
    }
    void display()
    {
        cout<<"         姓名:"<<name<<endl;
        cout<<"         年龄:"<<age<<endl;
        cout<<"         地址:"<<add<<endl;
        cout<<"         电话:"<<phone<<endl;
    }
protected:
    string position;
};
class Cadre:virtual public person//虚基类
{
public:
    Cadre(string name,int age,string sex,string add,string phone,string Post):person(name,age,sex,add,phone)
    {
        post=Post;
    }
protected:
    string post;
};
class TeacherCadre:public Teacher,public Cadre
{
public:
    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)
                 {
                     wage=Wage;
                 }
    void show()
    {
        Teacher::display();
        cout<<"         职务:"<<post<<endl;
        cout<<"         工资:"<<wage<<endl;
    }
protected:
    double wage;
};
int main()
{
    TeacherCadre t1("张三",32,"男","北京","1878****454","教导主任","老师",7856.34);
    t1.show();
}
结果:
姓名:张三
年龄:32
地址:北京
电话:1878****454
职务:老师
工资:7856.34

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

例如:我们把虚基类的构造函数改为
person(string Name,int Age,string Sex,string Add,string Phone)
    {
        name=Name;
        age=Age;
        sex=Sex;
        add=Add;
        phone=Phone;
        cout<<"秋水共长天一色,落霞与孤鹜齐飞"<<endl;
    }
看一下运行结果:
秋水共长天一色,落霞与孤鹜齐飞
         姓名:张三
         年龄:32
         地址:北京
         电话:1878****454
         职务:老师
         工资:7856.34
所以虚基类的构造函数真的只调用了一次,那就是最后一个的派生类调用了虚基类的构造函数

🌸总结

派生类构造函数调用的次序有如下的3个原则
(1)同一层中对虚基类构造函数的调用优先于对非基类构造函数的调用
(2)若同一层次中包含多个虚基类,则这些虚基类的构造函数按照它们在继承方式中的声明次序调用。
(3)若虚基类由非基类派生出来,则仍然调用基类的构造函数,在按派生类中构造函数的执行顺序调用
派生类的析构函数调用次序与构造函数恰恰相反。

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

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

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐