临海大经建设集团网站,开网址,做网站被坑,免费动漫由于C支持多继承#xff0c;除了public、protected和private三种继承方式外#xff0c;还支持虚拟#xff08;virtual#xff09;继承#xff0c;举个例子#xff1a;
#include iostream
using namespace std;class A {};
class B : virtual public A {};
class…由于C支持多继承除了public、protected和private三种继承方式外还支持虚拟virtual继承举个例子
#include iostream
using namespace std;class A {};
class B : virtual public A {};
class C : virtual public A {};
class D : public B, public C {};int main()
{cout sizeof(A) sizeof A endl; // 1空对象只有一个占位cout sizeof(B) sizeof B endl; // 4一个bptr指针省去占位,不需要对齐cout sizeof(C) sizeof C endl; // 4一个bptr指针省去占位,不需要对齐cout sizeof(D) sizeof D endl; // 8两个bptr省去占位,不需要对齐
}/*sizeof(A)1sizeof(B)8sizeof(C)8sizeof(D)16
*/
上述代码所体现的关系是B和C虚拟继承AD又公有继承B和C这种方式是一种菱形继承或者钻石继承可以用如下图来表示 虚拟继承的情况下无论基类被继承多少次只会存在一个实体。**虚拟继承基类的子类中子类会增加某种形式的指针或者指向虚基类子对象或者指向一个相关的表格表格中存放的不是虚基类子对象的地址就是其偏移量此类指针被称为bptr如上图所示。如果既存在vptr又存在bptr某些编译器会将其优化合并为一个指针。 虚拟继承是一种多重继承的特殊形式它的目的是解决菱形继承中的冗余数据和二义性问题¹。
菱形继承是指一个派生类继承了两个或多个直接基类而这些直接基类又继承自同一个间接基类形成了一个菱形的继承结构²。例如
class A {// 间接基类
};class B: public A {// 直接基类
};class C: public A {// 直接基类
};class D: public B, public C {// 派生类
};
在这种情况下派生类 D 中会包含两份间接基类 A 的成员一份来自 B一份来自 C。这样会造成以下问题³
冗余数据派生类 D 中的两份 A 的成员占用了多余的内存空间而且可能存储了不一致的数据。二义性当派生类 D 中访问 A 的成员时编译器无法确定是访问 B 中的 A 还是 C 中的 A需要显式地指定路径否则会报错。
为了解决这些问题可以使用虚拟继承即在继承方式前加上 virtual 关键字表示该基类是一个虚拟基类例如 class A {// 间接基类
};class B: virtual public A {// 直接基类
};class C: virtual public A {// 直接基类
};class D: public B, public C {// 派生类
};
这样派生类 D 中就只保留了一份间接基类 A 的成员不会出现冗余数据和二义性问题。虚拟继承的原理是通过虚基指针和虚基表来实现的每个包含虚拟基类的类都有一个虚基指针指向一个虚基表虚基表中存放了虚拟基类的偏移量用于定位虚拟基类的位置⁴。
虚拟继承的作用是在多重继承的情况下保证间接基类的实例只会在派生类对象中存在一次而不会重复出现。这样可以避免数据的冗余和访问的二义性也可以节省内存空间和提高效率。虚拟继承是一种复杂的继承方式一般不推荐使用除非在必要的情况下。多重继承本身就容易引起设计上的混乱和错误所以在实际开发中应该尽量避免使用多重继承或者使用单一继承和组合的方式来代替多重继承。