C12虚继承
目录
C++12(虚继承)
虚继承
虚继承:
在C++中多继承时很容易产⽣命名冲突,即使我们很⼩⼼地将所有类中的成员变量和成员函数都命名为不同的名字,命名冲突依然有可能发⽣,⽐如典型的是菱形继承,如下图所示:
类 A 派⽣出类 B 和类 C,类 D 继承⾃类 B 和类 C,这个时候类 A 中的成员变量和成员函数继承到类 D 中变成了两份,⼀份来⾃ A–>B–>D 这条路径,另⼀份来⾃ A–>C–>D 这条路径
在⼀个派⽣类中保留间接基类的多份同名成员,虽然可以在不同的成员变量中分别存放不同的数据,但⼤多数情况下这是多余的:因为保留多份成员变量不仅占⽤较多的存储空间,还容易产⽣命名冲突。假如类 A 有⼀个成员变量 a,那么在类 D中直接访问 a 就会产⽣歧义,编译器不知道它究竟来⾃ A –>B–>D 这条路径,还是来⾃ A–>C–>D 这条路径。
#include <iostream>
using namespace std; //普通类的菱形继承:虚基类的成员会被拷⻉两份,⼀模⼀样的,导致了空间的浪费;
class A
{
public:
int a;
A()
{
a = 10;
}
};
class B:public A
{
public:
int c;
B()
{
c = 11;
}
};
class C:public A
{
public:
int d;
C()
{
d = 12;
}
};
class D :public B, public C
{
};
int main()
{
D dd;
cout << sizeof(dd) << endl; // 结构是16⽽不是12
cout << dd.a << endl;//调⽤时会报 访问对象不明确,可以在成员前加类名来限定
}
虚继承
为了解决多继承时的命名冲突和冗余数据问题,C++ 提出了虚继承,使得在派⽣类中只保留⼀份间接基类的成员。
#include <iostream>
using namespace std;
class A
{
public:
int a;
A()
{
a = 10;
}
};
class B: virtual public A
{
public:
int c;
B()
{
c = 11;
}
};
class C: virtual public A //让 B与C类采⽤虚继承。
{
public:
int d;
C()
{
d = 12;
}
};
class D :public B, public C
{
};
int main()
{
D dd;
cout << sizeof(dd) << endl; // 20 ,增加了8个字节维护虚继承产⽣的"虚信息"
cout << dd.a << endl; //10
}
//虚继承与虚函数的相似之处:都使⽤了虚指针(均占⽤类对象存储空间)和虚表均不占⽤类对象的存储空间)