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
分别继承自 Student
和 Worker
,并且三个类都有相同名称的 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
分别继承自 Student
和 Worker
, 并且三个类都有相同名称的 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, 内存排列顺序
-
- 虚表指针
-
- 自身成员变量
-
- 虚基类成员
-
- Undergraduate 正常继承自 Student 和 Worker,按照继承顺序内存排列
-
- 父类1 Student (虚表指针 、 父类成员【不包含虚基类成员】)
-
- 父类2 Worker (虚表指针 、 父类成员【不包含虚基类成员】)
-
- 自身成员变量
-
- 虚基类继承的成员变量
-