菱形继承的问题和内存布局
class Base
{
public:
Base(int){ std::cout << "Base()" << std::endl; };
~Base(){ std::cout << "~Base()" << std::endl; };
protected:
int n;
};
class A : public Base
{
public:
A(int a):Base(a){ std::cout << "A()" << std::endl; };
~A(){ std::cout << "~A()" << std::endl; };
protected:
int a;
};
class B : public Base
{
public:
B(int b):Base(b){ std::cout << "B()" << std::endl; };
~B(){ std::cout << "~B()" << std::endl; };
protected:
int b;
};
class C : public A,public B
{
public:
C(int c):Base(c),A(c),B(c){ std::cout << "C()" << std::endl; };
~C(){ std::cout << "~C()" << std::endl; };
protected:
int c;
};
class A 继承自class Base ,将Base::n 继承下来,class B 继承自class Base ,也将Base::n 继承下来
最后,class C 将class A 和class B 的内容继承下来,这样一来,class C 相当于继承了两份Base::n
这样class C的内存布局中会多余出Base::n,假如n占用了特别大的空间,无疑是对内存的浪费,效率低下。
使用虚继承解决菱形继承内存浪费问题
class A : virtual public Base
{
public:
A(int a):Base(a){ std::cout << "A()" << std::endl; };
~A(){ std::cout << "~A()" << std::endl; };
protected:
int a;
};
class B : virtual public Base
{
public:
B(int b):Base(b){ std::cout << "B()" << std::endl; };
~B(){ std::cout << "~B()" << std::endl; };
protected:
int b;
};
当进行虚继承时,虚基类的数据将会被放在内存布局的最后面,并且在原位置补充一个vbptr,指向内存布局的最后面。
这样保证虚基类的数据在对象内存上只有一份拷贝。
总结
菱形继承比较浪费内存,一般出现菱形继承的现象首先考虑设计上的问题,如果设计上的问题没法儿解决,那么使用虚继承进行处理。
菱形继承一般是个比较糟糕的设计,不推荐使用,但是作为学习者,有必要进行了解。
补充:
Base::n将由class C进行初始化,不是class A,也不是class B.
|