5多重继承那些事
多种继承那些事
理解虚基类和虚继承
抽象类:有虚函数的类
虚基类:被虚继承的类就称作虚基类
虚继承中派生类发生的内存变化
虚继承与多态相结合
class A
{
public:
virtual void func(){cout<<"Base::func"<<endl;}
private:
int ma;
};
class B:virtual public A //虚继承,A被B虚继承了,就称A为虚基类
{
public:
virtual void func(){cout<<"Derive::func"<<endl;}
private:
int mb;
};
int main()
{
A a;
B b;
// cout<<sizeof(a)<<" "<<sizeof(b)<<endl;
A* p = new B;
p->func();
delete p;
return 0;
}
这会抛出异常,下面解释原因
可以看到类B的内存布局,位于内存开始的是一个派生类对象,这与正常的继承或存在虚函数的继承不同(基类位于内存的开始地方),然后用一个基类的指针指向新分配的派生类对象(内存首部是子类)。
基类指针指向派生类对象永远指向派生类的基类部分数据的起始地址,但是在delete时只释放了基类的内存而没有释放派生类的内存导致内存泄漏,只需将基类中的虚构函数变成虚继承函数即可
菱形继承问题
class A
{
public:
A(){cout<<"A()"<<endl;}
~A(){cout<<"~A()"<<endl;}
protected:
int ma;
};
class B : virtual public A
{
public:
B(){cout<<"B()"<<endl;}
~B(){cout<<"~B()"<<endl;}
protected:
int mb;
};
class C : virtual public A
{
public:
C(){cout<<"C()"<<endl;}
~C(){cout<<"~C()"<<endl;}
protected:
int mc;
};
class D : public B,C
{
public:
D(){cout<<"D()"<<endl;}
~D(){cout<<"~D()"<<endl;}
protected:
int md;
};
int main()
{
D d;
cout<<sizeof(d)<<endl;
return 0;
}
输出:
A()
B()
A()
C()
D()
20 //两个ma 一个mb 一个 mc 一个md
~D()
~C()
~A()
~B()
~A()
这是一种设计的缺陷,再d生成时,A的构造函数被调用了两次,这意味着d对象中的类A部分重复了
将对A的继承方式改为虚继承:
#include <iostream>
using namespace std;
class A
{
public:
A(int data){cout<<"A()"<<endl;}
~A(){cout<<"~A()"<<endl;}
protected:
int ma;
};
class B : virtual public A
{
public:
B(int data)
:A(data)
{cout<<"B()"<<endl;}
~B(){cout<<"~B()"<<endl;}
protected:
int mb;
};
class C : virtual public A
{
public:
C(int data)
: A(data)
{cout<<"C()"<<endl;}
~C(){cout<<"~C()"<<endl;}
protected:
int mc;
};
class D : public B,C
{
public:
D(int data) //一定要主动调用A的构造函数,这里才是真正地为类中的A对象初始化操作。这个对象位于D对象的末尾位置
: A(data),B(data), C(data)
{cout<<"D()"<<endl;}
~D(){cout<<"~D()"<<endl;}
protected:
int md;
};
int main()
{
D d(1);
cout<<sizeof(d)<<endl;
return 0;
}
输出:
A()
B()
C()
D()
24
~D()
~C()
~B()
~A()
若存在指针指向问题,就要将基类的析构函数变为需析构函数