【问题标题】:C++ pure virtual multiple inheritance?C++纯虚拟多重继承?
【发布时间】:2014-11-06 12:31:39
【问题描述】:

对于使用接口的多重继承的实现,我需要帮助...

有一个现有的代码,其接口具有很多功能。实例是使用工厂创建的。

class IBig
{
    // Lot of pure virtual functions
};

以及他的实现:

class CBig: public IBig
{
    // Implementation
}

我想将接口拆分为多个较小的接口,但它应该在一段时间内与现有代码保持兼容。

这是我尝试做的一个示例:

class IBaseA
{
public:
    virtual void DoA() = 0;
};

class IBaseB
{
public:
    virtual void DoB() = 0;
};

// The same interface, now based on multiple smaller interfaces
class IBig : public IBaseA, public IBaseB
{
};

class CBaseA: public IBaseA
{
public:
    virtual void DoA()
    {
        printf("DoA\n");
    }
};

class CBaseB: public IBaseB
{
public:
    virtual void DoB()
    {
        printf("DoB\n");
    }
};

// Inherit from base classes where the implementation is, and from IBig as 
// the instance of CBig is returned as IBig.
class CBig: public CBaseA, public CBaseB, public IBig
{
};

这里的问题是无法实例化 CBig 类。编译器说函数 DoA 和 DoB 是纯虚函数,即使它们在 CBaseA 和 CBaseB 中实现。不想再实现函数,只调用基类的函数怎么办?

NB:我知道设计很丑,但这只是暂时的,直到可以更换大界面,并且....我想了解! ;-)

提前致谢!

【问题讨论】:

  • 我认为你不需要在CBig声明中继承IBig。您已经拆分了 IBig,并且已经继承了 DoA() 和 DoB()。只需从 CBig 的声明中删除 IBig。
  • 感谢您的评论。这样做将不允许我将 CBig 实例返回为 IBig :-S

标签: c++ inheritance virtual multiple-inheritance


【解决方案1】:

这里你应该使用虚拟继承。此功能可确保在实例化子类时只有一个虚拟继承的基类实例。对于您的示例,这看起来像:

#include <cstdio>

class IBaseA
{
public:
    virtual void DoA() = 0;
};

class IBaseB
{
public:
    virtual void DoB() = 0;
};

// The same interface, now based on multiple smaller interfaces
class IBig : virtual public IBaseA,  virtual public IBaseB
//              ^                       ^
{
};

class CBaseA: virtual public IBaseA
//              ^
{
public:
    virtual void DoA()
    {
        printf("DoA\n");
    }
};

class CBaseB: virtual public IBaseB
//              ^
{
public:
    virtual void DoB()
    {
        printf("DoB\n");
    }
};

// Inherit from base classes where the implementation is, and from IBig as 
// the instance of CBig is returned as IBig.
class CBig: public CBaseA, public CBaseB, public IBig
{
};

int main()
{
    CBig cb;
}

上述更改确保在您多次继承IBaseAIBaseB 时不会创建额外的DoADoB 声明。

【讨论】:

  • 感谢您的解决方案和解释!
  • 对第二句稍作澄清:所有的 virtual 基础都合并为一个。相同类型的非虚拟基础仍然彼此不同,并且与虚拟基础不同。这样的构造通常是错误的:碱基通常应该是全虚拟的或全是非虚拟的。
  • 我认为这将在我的回答中隐含,但我会补充说明以避免歧义,谢谢。
【解决方案2】:

这被称为致命的死亡钻石(或简称钻石问题)。这是因为 CBig 继承自共享公共基类的类。

您可以通过为其所属的类添加前缀来调用正确的 DoA

CBaseA::doA();

或者你使用虚拟继承只有一个 IBaseA 和 IBaseB 的实例

class CBaseA : public virtual IBaseA {};
class CBaseB : public virtual IBaseB {};
class IBig : public virtual IBaseA, public virtual IBaseB {};

等等……

【讨论】:

  • 我把它称为“路西法火湖和熔岩硫磺中永恒诅咒的钻石”或简称 TDOEDILLOFAMB。
猜你喜欢
  • 2012-10-11
  • 2017-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-22
  • 2015-11-21
相关资源
最近更新 更多