C++中菱形类关系再理解

很多很多年前,还在北京读研时,我去 magnetar 寻求一个实习机会时,面我的北美小哥让我解释一下C++的菱形关系,好像当时没有答上来。

今天在 OceanBase 代码里又看到了菱形关系。多重继承在我们的代码中是很少出现的,居然能再次遇到可真不容易。

问题:下面的代码里,C 的构造函数为什么必须显式调用 Base(v)?

class Base {  explicit A(int &) {} }
class A : virtual public Base { }
class B : virtual public Base { }
class C :  public A, public B 
{
   C(int v) : Base(v), A(), B() {}
}

更进一步地,为什么下面比较简单的场景里 C 依然要显式调用 Base(v)?

class Base {  explicit A(int &) {} }
class A : virtual public Base { }
class C :  public A
{
   C(int v) : Base(v), A() {}
}

Well,有了一些工作经验后会积累一些设计的思想,能够更好地站在设计者角度思考问题。回答上面两个问题就比较容易了:

C++ 设计者引入了一条简单规则:A、B 这样使用了 virtual 继承的对象作为中间类时,没有资格去实例化基类。

还是有点绕,更简单的思维:

A、B 这样使用了 virtual 继承的对象作为中间类时,不会为A、B 分配基类对象的结构。

只要不让他们去分配对象,那么自然就需要子类去分配对象,子类分配了对象,自然就需要主动调用 Base 的构造函数。

C++设计者面对菱形问题时,解决思维如下:

  1. 要避免给基类(Base)分配多份内存
  2. 所以子类 A、B 都不应该去给基类(Base)分配内存
  3. 所以内存只能由 A、B 的子类 C 去分配内存
  4. 所以 C 需要调用构造函数。

然后遇到一个特殊情况:

  1. 如果 Base 只有一个子类 A,A 只有一个子类 C,那么 A 能不能为 Base 分配内存呢?
  2. 这里如果考虑极致优化,此时可以让 A 给 Base 分配内存,C无需关注 Base。
  3. 但是这样做太特殊。所以设计者保持了一致的用户接口:Base 的内存必须由 C 分配。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值