【问题标题】:C++ interfaces and inheritanceC++ 接口和继承
【发布时间】:2011-07-31 17:00:18
【问题描述】:

我想要一个接口 IA 和另一个扩展它的 IB。

A 实现 IA,B 继承 A 并实现 IB。

但是,当编译 B 时出现错误,说 IA 的东西是未定义的,即使 A 定义了它:(

class IA
{
public:
    virtual ~IA(){}
    virtual void foo()=0;
};
class IB : public IA
{
public:
    virtual void bar()=0;
};


class A : public IA
{
public:
    A();
    void foo();
};
class B : public A, public IB
{
public:
    B();
    void bar();
};

错误 C2259:“B”:无法实例化抽象类
由于以下成员:
'void IA::foo(void)' : 是抽象的

【问题讨论】:

  • @SteveJessop:什么版本? 4.1.2 rejects it, as does 4.3.4.
  • 使用 A:foo 似乎没有帮助
  • @Tomalak:我的main 函数中有一个错字(好吧,想想吧),我实例化了A 而不是B
  • 您必须使用虚拟继承。 IB::foo() 来自 IA 类在 B 类中未声明。 A::foo() 看起来一样,但事实并非如此。虚拟继承将“合并”这些功能。

标签: c++ inheritance interface


【解决方案1】:

查看 C++ 常见问题解答,从以下几点开始:https://isocpp.org/wiki/faq/multiple-inheritance#mi-diamond

它详细解释了“可怕的钻石”和虚拟继承。

【讨论】:

  • +1 该死的我太慢了。我公司愚蠢的门户代理服务器和内容检查软件......
  • @wheaties:这不是一场比赛。 :)
  • @Tomalak:你什么意思?只有第一个回答问题的老鼠(即使回答了一半)才能得到奶酪!
  • 好的,所以我虚拟继承了接口,它似乎工作。但现在我收到“警告 C4250:'B':通过支配继承 'A::A::foo'”。 msdn 页面似乎只是在说明它是什么,而不是在没有#pragma 警告来终止该警告的情况下如何摆脱它......我认为有一种特殊的方法可以做不会产生编译警告的事情?
  • @will:使用不那么奇怪的继承树。 :) (鸭子)
【解决方案2】:

(不,A 没有定义任何东西。您声明了 A()void foo(),但您没有定义它们。)

真正的问题是你的多重继承。

       B
     /   \
   A      IB
  /         \
IA          IA

如您所见,您的继承树中有两个“版本”IA,并且只有 A 实现了 void IA::foo(不过,正如我上面提到的,这会给您一个链接器错误,就像您没有'不定义实现)。

void IB::IA::foo() 仍未实现;因此,B 本身“继承了抽象性”,您无法实例化它。

B 也必须实现 void foo(),或者您可以使用虚拟继承来绕过它。

【讨论】:

  • 这不是问题。您不能实例化抽象类。这是一个 C++ 标准。
  • @AdrianMar:是的,我知道抽象类是什么。我正在编辑我的答案。 :)
  • 我明白了,那么对不起。 :) 删除 - 并添加 +。 :)
【解决方案3】:

这是真正完全合理的虚拟继承案例,但并不总是一种设计味道。

在并行层次结构接口/实现的情况下,“任何类->接口”形式的每个继承关系都应标记为虚拟:class A : public virtual IAclass B : public virtual IB, public Aclass IB : public virtual IA

这样,很可能(取决于实现,但至少在概念上),一个额外的指针存储在每个虚拟派生类中,以知道它应该在哪里找到它的虚拟基。 ABIB 类将有一个指向IA 的指针,而B 类将有一个指向IB 的指针。每个虚拟基地也将有自己的 vtable。

“可怕的菱形”的观点在图形上很好,但关键是派生类应该知道它们将使用的基类驻留在哪里,这就是虚拟继承的作用。您显然需要 vtable每个接口在这里,虚拟继承允许你做到这一点。

然后你可以继续并行,并添加额外的类CIC等等,记住:

当你继承一个接口时,虚拟继承。

顺便说一下,COM 类有类似的设计。

【讨论】:

  • +1 用于突出显示“无论何时继承接口,虚拟继承”
【解决方案4】:

您有 两个 foo() 副本,一个从 IB::IA 继承,一个从 A::IA 继承。其中只有一个在 A 中具有非抽象版本。

【讨论】:

    猜你喜欢
    • 2021-08-10
    • 1970-01-01
    • 2011-03-24
    • 1970-01-01
    • 2023-03-14
    • 2018-04-30
    • 2014-02-18
    • 2022-01-25
    相关资源
    最近更新 更多