欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【C++深度解析】38、被遗弃的多重继承

程序员文章站 2022-05-29 17:49:11
...

1 何为多重继承

C++允许一个类拥有多个父类,这就是多重继承

  • 子类拥有所有父类的成员变量
  • 子类继承所有父类的成员函数
  • 子类对象可以当作任意父类对象使用

多重继承的语法规则:
【C++深度解析】38、被遗弃的多重继承

// 38-1.cpp
#include<iostream>
using namespace std;
class BaseA
{
    int ma;
public:
    BaseA(int a) { ma = a; }
    int getA() { return ma; }
};

class BaseB
{
    int mb;
public:
    BaseB(int b) { mb = b; }
    int getB() { return mb; }
};

class Derived : public BaseA, public BaseB
{
    int mc;
public:
    Derived(int a, int b, int c) : BaseA(a), BaseB(b)
    {
        mc = c;
    }
    int getC() { return mc; }
    void print()
    {
        cout << "ma = " << getA() << ", "
            <<"mb = " << getB() << ", "
            << "mc = " << mc << endl;
    }
};
int main()
{
    cout << "sizeof(Derived) = " << sizeof(Derived) << endl;
    Derived d(1, 2, 3);
    d.print();
    cout << "d.getA() = " << d.getA() << endl;
    cout << "d.getB() = " << d.getB() << endl;
    cout << "d.getC() = " << d.getC() << endl;
    cout << endl;

    BaseA* pa = &d;
    BaseB* pb = &d;

    cout << "pa->getA() = " << pa->getA() << endl;
    cout << "pb->getB() = " << pb->getB() << endl;
    cout << endl;

    cout << "pa = " << pa << endl;
    cout << "pb = " << pb << endl;
    return 0;
}
  • 类 Derived 继承了类 BaseA 和类 BaseB,子类是由父类成员叠加子类得到的,所以类 Derived 拥有成员变量 ma,mb,mc。计算类对象大小时,计算的是成员变量的大小,成员函数保存在代码段,不计入对象大小。所以类 Derived 大小为 12。
  • Derived 对象可以调用继承来的成员函数 getA() ,getB()
  • 子类对象可以转换为任意父类对象使用,所以程序第 46-50 行可以转换为两个父类对象,调用父类函数
  • 程序第 53-54行打印指向对象 d 的两个指针来说明多重继承的第一个问题

编译运行:

$ g++ 38-1.cpp -o 38-1
$ ./38-1
sizeof(Derived) = 12
ma = 1, mb = 2, mc = 3
d.getA() = 1
d.getB() = 2
d.getC() = 3

pa->getA() = 1
pb->getB() = 2

pa = 0x7ffee3d7e03c
pb = 0x7ffee3d7e040

运行结果和我们分析的一致,但是 pa,pb 都是指向对象 d 的指针,他们的值却不同。这就是第一个问题。

2 多重继承问题一

  • 通过多重继承得到的对象可能拥有“不同的地址”

如下图所示,两个指针指向一个对象,可能指向的位置不同,且目前没有解决方案。
【C++深度解析】38、被遗弃的多重继承

3 多重继承问题二

  • 多重继承可能产生冗余的成员

【C++深度解析】38、被遗弃的多重继承

当多重继承关系出现闭合时产生数据冗余的问题
解决方案:虚继承

  • 虚继承能够解决数据冗问题
  • 中间层父类不再关心顶层父类的初始化
  • 最终子类必须直接调用顶层父类的构造函数
#include <iostream>
#include <string>
using namespace std;
class People
{
    string m_name;
    int m_age;
public:
    People(string name, int age)
    {
        m_name = name;
        m_age = age;
    }
    void print()
    {
        cout << "Name = " << m_name << ", "
             << "Age = " << m_age << endl;
    }
};

class Teacher : virtual public People				// 虚继承
{
public:
    Teacher(string name, int age) : People(name, age)
    {
    }
};

class Student : virtual public People				// 虚继承
{
public:
    Student(string name, int age) : People(name, age)
    {
    }
};

class Doctor : public Teacher, public Student
{
public:
	// 最终子类必须直接调用顶层父类的构造函数
    Doctor(string name, int age) : Teacher(name, age), Student(name, age), People(name, age)
    {
    }
};
int main()
{
    Doctor d("Delphi", 33);
    d.print();
    return 0;
}

4 小结

1、C++支持多重继承的编程方式
2、多重继承的问题

  • 可能出现同一个对象地址不同的情况
  • 虚继承可以解决数据冗余的问题
相关标签: C++深度解析