面试题答案
一键面试菱形继承问题描述
菱形继承是指在多重继承体系中,一个派生类从多个直接基类继承,而这些直接基类又共同继承自同一个基类,形成菱形结构。例如,类D
从类B1
和B2
继承,而B1
和B2
又都从类A
继承,这种结构就像一个菱形。
菱形继承的弊端
- 数据冗余:由于
B1
和B2
都继承自A
,当D
继承B1
和B2
时,D
中会存在两份A
类的数据成员,造成空间浪费。 - 命名冲突:如果
A
类中有成员函数,D
对象在调用这些函数时可能会出现命名冲突,不知道应该调用B1
继承来的版本还是B2
继承来的版本。
虚继承解决菱形继承问题
- 虚继承原理:虚继承的核心思想是让共同的基类(如上述例子中的
A
)在最终的派生类(如D
)中只保留一份数据成员。在虚继承中,虚基类的成员只有一份实例被保留在最终派生类的对象中,而不是像普通继承那样每个直接基类都保留一份。 - 实现方式:在继承列表中使用
virtual
关键字声明虚继承。例如,class B1 : virtual public A
和class B2 : virtual public A
。这样,B1
和B2
在继承A
时采用虚继承方式。 - 内存布局不同:在普通继承中,最终派生类对象内存布局中会有多个来自共同基类的数据成员副本。而在虚继承中,最终派生类对象内存布局中只有一份虚基类的数据成员。通常,虚继承会引入一个虚基类指针,该指针指向虚基类数据成员的存储位置,以实现共享一份数据。
代码示例
#include <iostream>
// 基类A
class A {
public:
int data;
A() : data(0) {}
};
// 从A虚继承的类B1
class B1 : virtual public A {
public:
B1() {}
};
// 从A虚继承的类B2
class B2 : virtual public A {
public:
B2() {}
};
// 从B1和B2继承的类D
class D : public B1, public B2 {
public:
D() {
data = 10; // 此时只有一份data
}
};
int main() {
D d;
std::cout << "d.data: " << d.data << std::endl;
return 0;
}
上述代码中,D
类通过B1
和B2
虚继承自A
,保证D
中A
的数据成员data
只有一份,避免了菱形继承带来的弊端。