当前位置: 首页 > article >正文

C++中的多重继承

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

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

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

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

目录

🐰多重继承

🌸声明多重继承的方法

🌸多重继承派生类的构造函数与析构函数

🌸多重继承引起的二义性


🐰多重继承

定义:多重继承是指派生类具有两个或两个以上的直接基类

🌸声明多重继承的方法

多重继承可以看作是单继承的扩展,派生类和每个基类之间的关系可以看作是一个单继承。多重继承派生类的声明格式如下:

class 派生类名:(继承方式)基类名1,...,(继承方式)基类名n
{
    派生类新增的成员
}

其中不同的基类可以选择不同的继承方式

🌸多重继承派生类的构造函数与析构函数

多重继承方式,定义派生类构造函数的形式:

派生类名(总参数列表):基类名(参数表1),...,基类名n(参数n),新增的数据成员(参数1),...,新增数据成员(参数n)
{
    ;
}

其中,总参数列表必须包含完成所有基类数据成员初始化所需的参数。

多重继承方式下派生类的构造函数与单继承方式下派生类构造函数相似,但同时负责该派生类所有基类构造函数的调用。构造函数调用的顺序为:先调用所有基类的构造函数,再执行派生类构造函数的函数体。所有基类构造函数的调用顺序将按照它们在继承方式中的声明次序调用,而不是按派生类构造函数参数初始化列表中的书写次序调用。

例如:

#include<iostream>
using namespace std;
class Base1
{
public:
    Base1(int BAse1)
    {
        cout<<"调用了Base1的构造函数"<<endl;
        base1=BAse1;
    }
    ~Base1()
    {
        cout<<"调用了Base1的析构函数"<<endl;
    }
protected:
    int base1;
};
class Base2
{
public:
    Base2(int BAse2)
    {
        cout<<"调用了Base2的构造函数"<<endl;
        base2=BAse2;
    }
    ~Base2()
    {
        cout<<"调用了Base2的析构函数"<<endl;
    }
protected:
    int base2;
};
class Base3:public Base1,public Base2
{
public:
    Base3(int BAse1,int BAse2,int BAse3):Base1(BAse1),Base2(BAse2)
    {
        cout<<"调用了Base3的构造函数"<<endl;
        base3=BAse3;
    }
    ~Base3()
    {
        cout<<"调用了Base3的析构函数"<<endl;
    }
private:
    int base3;
};
int main()
{
    Base3 s1(520,13,14);
}

运行结果:
调用了Base1的构造函数
调用了Base2的构造函数
调用了Base3的构造函数
调用了Base3的析构函数
调用了Base2的析构函数
调用了Base1的析构函数

派生类析构函数的执行,多重继承方式也与单继承方式类似。派生类析构函数的执行顺序,首先执行派生类析构函数的函数体,对派生类新增的数据成员所涉及的额外内存空间清理,然后调用基类的析构函数,对从基类继承来的成员所涉及的额外内存空间进行清理。所有基类的析构函数将按照它们在继承方式中的声明次序的逆序、从右向左调用(与其构造函数执行顺序正好相反)。

🌸多重继承引起的二义性

在多重继承的方式下,派生类继承了多个基类的成员。如果在这多个基类中拥有同名的成员,那么,派生类在继承各个基类的成员之后,当调用该派生类的这些同名成员时,就会出现二义性,编译器无法确定应该选择派生类哪一个成员。

二义性主要分为以下3种类型:

(1)两个基类有同名成员

#include<iostream>
using namespace std;
class Sofa
{
public:
    Sofa(string Name):name(Name)
    {
        cout<<"The is Sofa construction"<<endl;
    }
    void show()
    {
        cout<<"name="<<name<<endl;
    }
protected:
    string name;
};
class Bed
{
public:
    Bed(string Name):name(Name)
    {
        cout<<"The is Bed construction"<<endl;
    }
    void show()
    {
        cout<<"name="<<name<<endl;
    }
protected:
    string name;
};
class SofaBed:public Sofa,public Bed
{
public:
    SofaBed(string Name1,string Name2,string Name3):Sofa(Name1),Bed(Name2),name(Name3)
    {
        cout<<"The is Sofa construction"<<endl;
    }
    void disshow()
    {
        cout<<"name="<<name<<endl;//虽然和基类Sofa和Bed的数据成员名一样,但是在派生类中会被重写
        cout<<"name="<<Bed::name<<endl;
        cout<<"name="<<Sofa::name<<endl;
        cout<<"name="<<SofaBed::name<<endl;
    }
protected:
    string name;
};
int main()
{
    SofaBed s1("沙发","床","沙发床");
//    s1.show();//这里会出现二义性,因为无法知道这个show函数是基类Sofa和Bed的那一个的
    s1.Sofa::show();
    s1.Bed::show();
    s1.disshow();
}
结果:
The is Sofa construction
The is Bed construction
The is Sofa construction
name=沙发
name=床
name=沙发床
name=床
name=沙发
name=沙发床

s1.show()为了解决这个二义性,我们可以使用类名来限定,如 s1.Sofa::show()s1.Bed::show()

(2)两个基类和派生类三者都有同名函数

#include<iostream>
using namespace std;
class Sofa
{
public:
    Sofa(string Name):name(Name)
    {
        cout<<"The is Sofa construction"<<endl;
    }
    void show()
    {
        cout<<"name="<<name<<endl;
    }
protected:
    string name;
};
class Bed
{
public:
    Bed(string Name):name(Name)
    {
        cout<<"The is Bed construction"<<endl;
    }
    void show()
    {
        cout<<"name="<<name<<endl;
    }
protected:
    string name;
};
class SofaBed:public Sofa,public Bed
{
public:
    SofaBed(string Name1,string Name2,string Name3):Sofa(Name1),Bed(Name2),name(Name3)
    {
        cout<<"The is Sofa construction"<<endl;
    }
    void show()
    {
        cout<<"name="<<name<<endl;//虽然和基类Sofa和Bed的数据成员名一样,但是在派生类中会被重写
        cout<<"name="<<Bed::name<<endl;
        cout<<"name="<<Sofa::name<<endl;
        cout<<"name="<<SofaBed::name<<endl;
    }
protected:
    string name;
};
int main()
{
    SofaBed s1("沙发","床","沙发床");
    s1.show();
}
结果:
The is Sofa construction
The is Bed construction
The is Sofa construction
name=沙发床
name=床
name=沙发
name=沙发床

程序能够正常编译,同时也能正常运行。show()虽然和基类Sofa和Bed的成员函数的声明一样,但是在派生类中会被重写

(3)如果两个基类从一个基类派生的

#include<iostream>
using namespace std;
class Wood
{
public:
    Wood()
    {
        cout<<"The is Wood construction"<<endl;
    }
    void Show()
    {
        cout<<"name="<<name<<endl;
    }
protected:
    string name="木头";
};
class Sofa:public Wood
{
public:
    Sofa(string Name):name(Name)
    {
        cout<<"The is Sofa construction"<<endl;
    }
    void show()
    {
        cout<<"name="<<name<<endl;
    }
protected:
    string name;
};
class Bed:public Wood
{
public:
    Bed(string Name):name(Name)
    {
        cout<<"The is Bed construction"<<endl;
    }
    void show()
    {
        cout<<"name="<<name<<endl;
    }
protected:
    string name;
};
class SofaBed:public Sofa,public Bed
{
public:
    SofaBed(string Name1,string Name2,string Name3):Sofa(Name1),Bed(Name2),name(Name3)
    {
        cout<<"The is Sofa construction"<<endl;
    }
    void disshow()
    {
        cout<<"name="<<name<<endl;//虽然和基类Sofa和Bed的数据成员名一样,但是在派生类中会被重写
        cout<<"name="<<Bed::name<<endl;
        cout<<"name="<<Sofa::name<<endl;
        cout<<"name="<<SofaBed::name<<endl;
    }
protected:
    string name;
};
int main()
{
    SofaBed s1("沙发","床","沙发床");
    s1.Sofa::Show();
    s1.Bed::Show();
}
结果:
The is Wood construction
The is Sofa construction
The is Wood construction
The is Bed construction
The is Sofa construction
name=木头
name=木头

SafaBed的两个基类Safa和Bed从一个基类Wood派生。虽然在类Safa和Bed中没有定义成员函数Show,但是它们都从Show中继承了成员函数,这样类Safa和Bed中同时存在同名的成员函数Show。如果在main函数中用派生类SofaBed创建一个对象,s1,并调用Show,不能直接用s1.Show()或者s1.Wood::Show()。因为无法判断是从基类Safa和Bed那一个继承的。如果要调用应该这样

s1.Sofa::Show();

s1.Bed::Show();

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

 


http://www.kler.cn/a/4828.html

相关文章:

  • fitz获取pdf内容
  • 【Rust自学】11.10. 集成测试
  • git提交
  • 【机器学习:八、逻辑回归】
  • 如何评价2023美赛春季赛YZ题加赛 大学生数学建模
  • mybatis核心配置文件
  • Java Web程序设计——Servlet的认识和创建
  • 【Linux】进程程序替换
  • Spring入门篇7 --- spring事务
  • HTTP 重定向状态码是什么意思?
  • 组提交_并行复制
  • FITC-PEG-SH,荧光素-聚乙二醇-巯基的用途:用于修饰氨基酸,蛋白质等
  • day9—编程题
  • 软件测试零基础好入门么
  • 电力行业等保定级评级依据是什么?分为几个等级?
  • 分布式锁实现方案
  • 【Note2】macvlan,sol
  • 【蓝桥杯-筑基篇】搜索
  • 微信小程序商城系统必须配置SSL证书吗?
  • 中国版ChatGPT在哪些方面具有快速发展的机会?
  • Ubuntu之NVIDIA GeForce显卡驱动安装
  • Redis 基本数据类型
  • 辉煌优配|猪肉概念股大幅拉升,巨星农牧涨停
  • Docker 安装 Redis