首页 > 编程语言 >什么是 C++ 中的多继承?它有哪些优缺点? 什么是虚继承?为什么要使用虚继承?

什么是 C++ 中的多继承?它有哪些优缺点? 什么是虚继承?为什么要使用虚继承?

时间:2024-11-26 19:29:55浏览次数:6  
标签:二义性 继承 优缺点 C++ class int 基类 public

1)什么是 C++ 中的多继承?它有哪些优缺点?

一、多继承的定义

在 C++中,多继承是指一个类可以从多个基类继承成员。

例如:

class Base1 {
public:
    void func1() {
        //...
    }
};

class Base2 {
public:
    void func2() {
        //...
    }
};

class Derived : public Base1, public Base2 {
};

在这个例子中, Derived 类同时继承了 Base1 和 Base2 两个类。

二、多继承的优点

1. 代码复用性高

可以从多个不同的类中继承功能,避免重复编写代码。

例如,一个图形绘制程序中,可能有一个表示形状的基类和一个表示颜色的基类,通过多继承可以创建一个既具有形状属性又具有颜色属性的具体图形类。

2. 灵活性强

可以根据具体需求组合不同的基类功能,实现更加复杂的类层次结构。

比如,一个游戏角色类可以同时继承表示移动能力的基类、表示攻击能力的基类和表示生命值管理的基类等。

三、多继承的缺点

1. 二义性问题

当多个基类中存在同名成员时,在派生类中访问该成员可能会产生二义性。例如:

class Base1 {
public:
    int value;
};

class Base2 {
public:
    int value;
};

class Derived : public Base1, public Base2 {
public:
    void printValue() {
        // 这里访问 value 会产生二义性
        std::cout << value << std::endl;
    }
};

解决二义性需要使用作用域解析运算符明确指定访问哪个基类的成员。

2. 复杂性增加

多继承使得类的层次结构变得更加复杂,难以理解和维护。特别是当继承层次较深时,可能会导致代码的可读性和可维护性降低。

3. 菱形继承问题

多继承可能导致菱形继承问题,即两个派生类继承同一个基类,然后又有一个类同时继承这两个派生类。这可能会导致在派生类中存在多份基类的子对象,浪费内存空间并且可能引发二义性问题。可以通过虚继承来解决菱形继承问题,但这又增加了代码的复杂性。

2) 什么是虚继承?为什么要使用虚继承?

一、虚继承的定义

在 C++中,虚继承是一种继承方式,用于解决多继承时可能出现的重复继承同一个基类的问题。

当一个类以虚继承的方式继承基类时,在派生类的对象布局中,只会存在一份基类的子对象,而无论有多少条继承路径指向该基类。

例如:

class Base {
public:
    int data;
};

class Derived1 : virtual public Base {
};

class Derived2 : virtual public Base {
};

class MostDerived : public Derived1, public Derived2 {
};

 在这个例子中, MostDerived 类通过 Derived1 和 Derived2 间接虚继承了 Base 类,在 MostDerived 类的对象中只会有一份 Base 类的子对象。

二、使用虚继承的原因

1. 避免二义性

在多继承中,如果多个基类中有同名成员,且没有使用虚继承,那么在派生类中访问该成员时可能会产生二义性。而通过虚继承,派生类对象中只有一份基类的子对象,避免了这种二义性。

class Base {
public:
    int value;
};

class Derived1 : public Base {
};

class Derived2 : public Base {
};

class MostDerived : public Derived1, public Derived2 {
public:
    void printValue() {
        // 如果没有虚继承,这里访问 value 会产生二义性
        std::cout << value << std::endl;
    }
};

 2. 节省内存空间

当存在复杂的继承层次结构时,如果不使用虚继承,可能会导致多个基类子对象在派生类对象中重复存储,浪费内存空间。而虚继承可以确保只存在一份基类子对象,节省内存。

虚继承在 C++中是一种解决多继承问题的重要手段,可以避免二义性和节省内存空间。

3.解决菱形继承问题

非虚继承:

class A
{
public:
	int a;
};
class B :public A
{
public:
	int b;
};
class C :public A
{
public:
	int c;
};
class D :public B, public C
{
public:
	int d;
};

int main()
{
	D d;
	d.a;
	return 0;
}

非虚继承会出现下图状况:产生菱形继承的二义性,D::a不明确

非虚继承时,D类中的内存情况:

虚继承:

class A
{
public:
	int a;
};
class B :virtual public A
{
public:
	int b;
};
class C :virtual public A
{
public:
	int c;
};
class D :public B, public C
{
public:
	int d;
};

int main()
{
	D d;
	d.a;
	return 0;
}

使用虚继承解决了菱形继承问题:

虚继承时,D类中的内存情况

4.虚继承原理

在虚继承中,会定义一个虚基表指针vbptr,指向虚基表而虚基表中会存在偏移量,这个量就是表的地址到父类数据地址的距离

标签:二义性,继承,优缺点,C++,class,int,基类,public
From: https://blog.csdn.net/SUN_Gyq/article/details/144066285

相关文章

  • C++ 1112 超标区间 (乙级)
    上图是用某科学研究中采集的数据绘制成的折线图,其中红色横线表示正常数据的阈值(在此图阈值是25)。你的任务就是把超出阈值的非正常数据所在的区间找出来。例如上图中横轴[3,5]区间中的3个数据点超标,横轴上点9(可以表示为区间[9,9])对应的数据点也超标。输入格式:输......
  • NTFS Permissions Reporter 与 Albus Bit NTFS Permissions Auditor Pro 两款工具的对
    NTFSPermissionsReporter与AlbusBitNTFSPermissionsAuditorPro两款工具的对比表格,展示它们在功能、优缺点、适用场景等方面的主要区别:功能/特点NTFSPermissionsReporterAlbusBitNTFSPermissionsAuditorPro主要功能文件权限审计、报告生成、权限继承......
  • 【类的默认成员函数】构造函数&&析构函数【C++】
    【类的默认成员函数】构造函数&&析构函数【C++】任何一个类在我们不写的情况下,都会自动生成6个默认成员函数构造函数:初始化(不是开空间!)日常实操中最好自己写一个!!!!!!!!Date(){ _year=1; _month=1; _day=1;}特点(1)函数名和类名相同(2)无返回值(3)对象实例化时编译器自动调......
  • explicit关键字【C++】
    explicit关键字【C++】用来修饰只有一个参数的类构造函数,以表明该构造函数是显式的,而非隐式的禁止类对象之间的隐式转换,以及禁止隐式调用拷贝构造函数隐式类型转换inti=1;doubled=i;d被i赋值时【编译器会做】在中间产生一个临时变量再通过这个临时对象进行拷贝构......
  • C++练级计划->《多态》虚函数表,菱形继承多态
    目录什么是多态?多态的条件虚函数:虚函数的重写:协变 析构函数的重写C++11final和overridefinal:override:总结:三重对比:重载重写重定义对比抽象类多态的原理虚函数表为什么只能是父类的指针或者引用来调用才能形成多态? 动态绑定和静态绑定单继承的虚函数表 ......
  • 杨辉三角 c++
    第一种输出图形(直角三角形) #include<cstdio>#include<iostream>usingnamespacestd;voidyh(inta[10][10],intn){//定义n<10 for(inti=1;i<=n;i++){ for(intj=1;j<=n;j++){ if(i==j||j==1){//杨辉三角每行首尾都为1 a[i][j]=1; } elsea[i][......
  • C++,引用的讲解,本质,用法,注意事项
    1.引用的语法引用实际上就是给变量起别名,语法:数据类型&别名=原名,代码举例如下:#include<iostream>usingnamespacestd;intmain(){ inta=10; int&b=a; cout<<"a="<<a<<endl; cout<<"b="<<b<<end......
  • 树的双亲表示法与孩子表示法(C++源码)
    目录一、双亲表示法:二、孩子表示法:一、双亲表示法:#include<iostream>usingnamespacestd;#defineMAX_TREE_SIZE100template<typenameDataType>structPNode{ DataTypedata; intparent;};//树的存储结构:双亲表示法template<typenameDataType......
  • 打卡信奥刷题(309)用C++信奥P2614[普及组/提高] 计算器弹琴
    计算器弹琴题目描述总所周知,计算器可以拿来干很多它本不应该干的事情,比如写作文。(参看洛谷P2549)小A发现了一个计算器的另一个隐藏功能——弹琴。http://www.bilibili.com/video/av2205500/如果按上一个键,比如说1,就会发出中音“Do”。这边给出按键音高表+低音Fa<低......
  • C++子串计算
    内存限制:64MB时间限制:1.000S题目描述给出一个只包含0和1的字符串(长度在1到100之间),求其每一个子串出现的次数。输入一行,一个01字符串。输出对所有出现次数在1次以上的子串,输出该子串及出现次数,中间用单个空格隔开。按子串的字典序从小到大依次输出,每行一个。样例输入......