菱形继承中虚基类,虚基表指针

虚基类

1.概念

当在多条继承路径上有一个公共的基类< 菱形继承>,在这些路径中的某几条汇合处,这个公共的基类就会产生多个实例(或多个副本),若只想保存这个基类的一个实例,可以将这个公共基类说明为虚基类。所以虚基类的作用是为了保证虚基类在派生类中只被继承一次。

如图:A为公共基类

在这里插入图片描述

类D中有两个int a,这不仅没有意义,还浪费空间,显然是不合理的,所以引入虚基类,来解决这个问题。

2.声明格式

class A
{
	int a;
public:
	A(int x = 0) :a(x) {}
};
class B : virtual public A
{
	int b;
public:
	B(int x = 1) :A(x + 10), b(x) {}
};
class C : virtual public A
{
	int c;
public:
	C(int x = 2) :A(x + 10), c(x) {}
};
class D : public B, public C
{
	int d;
public:
	D(int x = 3) :B(x + 10), C(x + 5), d(x) {}
};

这样类D中就只有一份int a,可以有效的避免二义性,空间浪费。

虚继承与继承的区别:

多了一个虚基指针。
虚基类位于派生类存储空间的最末尾。
不会共用虚函数指针。

3.菱形虚继承的对象的内存分布图

虚指针所指向的虚基表的内容:

  1. 虚基指针的第一条内容表示的是该虚基指针距离所在的子对象的首地址的偏移
  2. 虚基指针的第二条内容表示的是该虚基指针距离虚基类子对象的首地址的偏移

b的内存分布图

c的内存分布图

d的内存分配图

在这里插入图片描述
2.

4虚拟继承中派生类对象的构造过程:

在派生类对象的创建中,首先是虚基类的构造函数并按它们声明的顺序构造。第二批是非虚基类的构
造函数按它们声明的顺序调用。第三批是成员对象的构造函数。最后是派生类自己的构造函数被调用。

//测试代码
class A
{ 
    int a;
public:   
    void display();
    A(int x = 5) :a(x) { cout << "Creat A " << endl; }
    ~A() { cout << "Destroy A" << endl; }
};
class B : virtual public A
{
    int b;
public: 
    B(int x = 1) :A(x) { cout << "Creat B " << endl; }
    ~B() { cout << "Destroy B" << endl; }
};
class C : virtual public A
{ 
    int c;
public:  
    C(int x = 0) :A(x) {cout << "Creat C " << endl;}
    ~C() { cout << "Destroy C" << endl; }
};
class D : public B, public C
{
    int d;
public: 
    D() :A(10), B(), C() { cout << "Creat D " << endl; }
    ~D() { cout << "Destroy D" << endl; }
};
int main()
{
    D d;
    return 0;
}

结果如图:

在这里插入图片描述

可以看到析构顺序和构建顺序相反,这是因为系统给函数分配的栈空间遵循后进先出规则

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值