cpp_multiple_inheritance - ShenYj/ShenYj.github.io GitHub Wiki

多继承

C++允许一个类可以有多个父类(不建议使用,会增加程序设计复杂度)

多继承-构造函数调用

struct Student {
    int m_score;

    Student(int score) {
        this->m_score = score;
    }
};

struct Worker {
    int m_salary;

    Worker(int salary) {
        this->m_salary = salary;
    }
};

/// 多继承, 并且指定了不同的继承权限
struct Undergraduate : private Student, puclic Worker {
    int m_age;

    Undergraduate(int age, int score, int salary): m_age(age), Student(score), Worker(salary) {
        
    }
};

.

多继承-虚函数

如果子类继承的多个父类都有虚函数,那么子类对象就会产生对应的多张虚表

.

多继承-同名函数

派生类 Undergraduate 分别继承自 StudentWorker,并且三个类都有相同名称的 eat 函数

class Student {

public:
    void eat() {
        cout << "Student::eat()" << endl;
    }
};

class Worker {
public:
    void eat() {
        cout << "Worker::eat()" << endl;
    }
};

class Undergraduate: public Student, public Worker {
public:
    void eat() {
        cout << "Undergraduate::eat()" << endl;
    }
};

此时如何调用派生类自己的函数,如何指定父类函数

int main() {
    /// 创建一个派生类的实例
    Undergraduate ug;
    /// 调用自己的
    ug.eat();
    /// 利用实例对象 ug 调用父类 Student 的 eat 函数
    ug.Student::eat();
    /// 利用实例对象 ug 调用父类 Worker 的 eat 函数
    ug.Worker::eat();
}

多继承-同名成员变量

派生类 Undergraduate 分别继承自 StudentWorker, 并且三个类都有相同名称的 m_age 成员变量

c++ 中允许这样定义, 此示例依然会分配12字节(三个m_age成员空间)

class Student {

public:
    int m_age;
};

class Worker {
public:
    int m_age;
};

class Undergraduate: public Student, public Worker {
public:
    int m_age;
};
int main() {
    /// 创建一个派生类的实例
    Undergraduate ug;
    /// 调用自己的 m_age 成员变量
    ug.m_age = 11;
    /// 利用实例对象 ug 调用父类 Student 的 m_age 成员变量
    ug.Student::m_age = 22;
    /// 利用实例对象 ug 调用父类 Worker 的 m_age 成员变量
    ug.Worker::m_age = 33;
}

菱形继承

  • 菱形继承带来的问题
    • 最底下子类从基类继承的成员变量冗余、重复
    • 最底下子类无法访问基类的成员,有二义性
class Person {
public:
    int m_age;
};

class Student: public Person {
public:
    int m_score;
};

class Worker: public Person {
public:
    int m_salary;
};

class Undergraduate: public Student, public Worker {
public:
    int m_grade;
};


int main() {

    /// ug 占用20字节
    /// Person 的棱形继承 导致 m_age 被两次继承,造成了内存空间的浪费
    Undergraduate ug;

    /// 编译报错, 程序无法辨别从 Student继承而来的成员,还是从 Worker 继承而来的
    //ug.m_age = 10;

    return 0;
}

Person 的棱形继承 导致 m_age 被两次继承,造成了内存空间的浪费

虚继承

  • 虚继承可以解决菱形继承带来的问题
class Person {
public:
    int m_age;
};

class Student: virtual public Person {
public:
    int m_score;
};

class Worker: virtual public Person {
public:
    int m_salary;
};

class Undergraduate: public Student, public Worker {
public:
    int m_grade;
};

上面的代码中, Person 类被称为 虚基类

Worker 和 Student 必须保证同时虚继承

int main() {

    /// ug 占用16字节
    /// 通过虚继承, 会共用 m_age 成员
    Undergraduate ug;

    /// 编译正常
    ug.m_age = 10;

    return 0;
}

.

如果不是虚继承,默认父类的成员会排在前面,但是虚继承后,父类的成员后放在后面,最前面仍然是虚表指针

  • Student 和 Worker 分别虚继承自 Person, 内存排列顺序
      1. 虚表指针
      1. 自身成员变量
      1. 虚基类成员
  • Undergraduate 正常继承自 Student 和 Worker,按照继承顺序内存排列
      1. 父类1 Student (虚表指针 、 父类成员【不包含虚基类成员】)
      1. 父类2 Worker (虚表指针 、 父类成员【不包含虚基类成员】)
      1. 自身成员变量
      1. 虚基类继承的成员变量
⚠️ **GitHub.com Fallback** ⚠️