是否需要从纯抽象类(接口)进行虚拟继承
为什么在下面的代码中编译器会抱怨 PureAbstractBase
是 MultiplyInheritedClass
的不明确基类?我意识到我在 MultiplyInheritedClass
中有两个 PureAbstractBase
副本,并且 FirstConreteClass
和 SecondConreteClass
应该虚拟地派生,因为它们是菱形的中间行(这确实解决了下面代码的问题)。但是,即使我有接口的两个副本,为什么 MultiplyInheritedClass 中的代码不只是重写两者并明确选择 MultiplyInheritedClass 中定义的接口类?
#include <iostream>
using namespace std;
class PureAbstractBase {
public:
virtual void interface() = 0;
};
// I know that changing the following line to:
// class FirstConcreteClass : public virtual PureAbstractBase {
// fixes the problem with this hierarchy
class FirstConcreteClass : public PureAbstractBase {
public:
virtual void interface() { implementation(); }
private:
void implementation() { cout << "This is object FirstConcreteClass\n"; }
};
// I know that changing the following line to:
// class SecondConcreteClass : public virtual PureAbstractBase {
// fixes the problem with this hierarchy
class SecondConcreteClass : public PureAbstractBase {
public:
virtual void interface() { implementation(); }
private:
void implementation() { cout << "This is object SecondConcreteClass\n"; }
};
class MultiplyInheritedClass : public FirstConcreteClass,
public SecondConcreteClass {
public:
virtual void interface() { implementation(); }
private:
void implementation() { cout << "This is object MultiplyInheritedClass\n"; }
};
此外,为什么我对以下层次结构没有问题?在这种情况下,ConcreteHandler 类不是具有 AbstractTaggingInterface 的三个副本吗?那么为什么它没有与上面的示例相同的问题呢?
#include <iostream>
using namespace std;
class AbstractTaggingInterface {
public:
virtual void taggingInterface() = 0;
};
class FirstAbstractHandler : public AbstractTaggingInterface {
public:
virtual void taggingInterface() { cout << "FirstAbstractHandler\n"; }
virtual void handleFirst() = 0;
};
class SecondAbstractHandler : public AbstractTaggingInterface {
public:
virtual void taggingInterface() { cout << "SecondAbstractHandler\n"; }
virtual void handleSecond() = 0;
};
class ThirdAbstractHandler : public AbstractTaggingInterface {
public:
virtual void taggingInterface() { cout << "ThridAbstractHandler\n"; }
virtual void handleThird() = 0;
};
class ConcreteHandler : public FirstAbstractHandler,
public SecondAbstractHandler,
public ThirdAbstractHandler {
public:
virtual void taggingInterface() = { cout << "ConcreteHandler\n"; }
virtual void handleFirst() {}
virtual void handleSecond() {}
virtual void handleThird() {}
};
我试图理解所有这些,因为我最近与一位同事进行了一次对话,他声称如果您从没有任何数据成员的纯虚拟类(接口)继承,则不需要虚拟继承。我认为理解为什么前一个代码示例不起作用而后者起作用将有助于在我的脑海中弄清楚这一点(并弄清楚他的评论的确切含义)。提前致谢。
Why is it that in the code below the compiler complains that PureAbstractBase
is an ambiguous base class of MultiplyInheritedClass
? I realize I have two copies of the PureAbstractBase
in MultiplyInheritedClass
and that FirstConreteClass
and SecondConreteClass
should be derived virtually because they're the middle row of the diamond (and that does indeed fix the problem with the code below). But even though I have two copies of the interface why is it that the code in MultiplyInheritedClass
does not just override both and unambiguously pick the interface class defined in MultiplyInheritedClass
?
#include <iostream>
using namespace std;
class PureAbstractBase {
public:
virtual void interface() = 0;
};
// I know that changing the following line to:
// class FirstConcreteClass : public virtual PureAbstractBase {
// fixes the problem with this hierarchy
class FirstConcreteClass : public PureAbstractBase {
public:
virtual void interface() { implementation(); }
private:
void implementation() { cout << "This is object FirstConcreteClass\n"; }
};
// I know that changing the following line to:
// class SecondConcreteClass : public virtual PureAbstractBase {
// fixes the problem with this hierarchy
class SecondConcreteClass : public PureAbstractBase {
public:
virtual void interface() { implementation(); }
private:
void implementation() { cout << "This is object SecondConcreteClass\n"; }
};
class MultiplyInheritedClass : public FirstConcreteClass,
public SecondConcreteClass {
public:
virtual void interface() { implementation(); }
private:
void implementation() { cout << "This is object MultiplyInheritedClass\n"; }
};
Further, why do I not have issues with the following hierarchy? Doesn't the ConcreteHandler class have three copies of the AbstractTaggingInterface in this case? So why doesn't it have the same issue as the example above?
#include <iostream>
using namespace std;
class AbstractTaggingInterface {
public:
virtual void taggingInterface() = 0;
};
class FirstAbstractHandler : public AbstractTaggingInterface {
public:
virtual void taggingInterface() { cout << "FirstAbstractHandler\n"; }
virtual void handleFirst() = 0;
};
class SecondAbstractHandler : public AbstractTaggingInterface {
public:
virtual void taggingInterface() { cout << "SecondAbstractHandler\n"; }
virtual void handleSecond() = 0;
};
class ThirdAbstractHandler : public AbstractTaggingInterface {
public:
virtual void taggingInterface() { cout << "ThridAbstractHandler\n"; }
virtual void handleThird() = 0;
};
class ConcreteHandler : public FirstAbstractHandler,
public SecondAbstractHandler,
public ThirdAbstractHandler {
public:
virtual void taggingInterface() = { cout << "ConcreteHandler\n"; }
virtual void handleFirst() {}
virtual void handleSecond() {}
virtual void handleThird() {}
};
I am trying to wrap my head around all of this because I had a conversation with a colleague recently where he claimed that if you were inheriting from pure virtual classes (interfaces) without any data members then virtual inheritance was not necessary. I think understanding why the former code example does not work and the latter does would go a long way to getting this straight in my head (and clear up what exactly he meant by his comment). Thanks in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您需要虚拟继承来克服菱形歧义:
冗长的解释:假设您有这样的情况:
虚拟函数
foo
的继承是不明确的,因为它以三种方式出现:来自B1< /code>,来自
B2
和来自A
。继承图形成一个“菱形”:通过将继承设置为虚拟,
struct B1 : public virtual A;
等,您允许C*
的任何基类调用正确的成员:我们必须还定义
C::foo()
才能使其有意义,否则C
将没有明确定义的成员foo
。更多细节:假设我们现在有一个正确的虚拟继承类
C
,如上所述。我们可以根据需要访问所有各种虚拟成员:
更新:正如 David 在评论中所说,这里的重点是中间类
B1
和B2
虚拟地继承,以便进一步的类(在这种情况下C
)可以从它们继承,同时保持从A
继承的明确性。对于最初的错误表示歉意,并感谢您的更正!You need virtual inheritance to overcome the diamond-ambiguity:
Long-winded explanation: Suppose you have this:
The inheritance of the virtual function
foo
is ambiguous because it comes in three ways: fromB1
, fromB2
and fromA
. The inheritance diagram forms a "diamond":By making the inheritance virtual,
struct B1 : public virtual A;
etc., you allow any baseclass ofC*
to call the correct member:We must also define
C::foo()
for this to make sense, as otherwiseC
would not have a well-defined memberfoo
.Some more details: Suppose we now have a properly virtually-inheriting class
C
as above. We can access all the various virtual members as desired:Update: As David says in the comment, the important point here is that the intermediate classes
B1
andB2
inherit virtually so that further classes (in this caseC
) can inherit from them while simultaneously keeping the inheritance fromA
unambiguous. Sorry for the initial mistake and thanks for the correction!您的第一个示例失败了,因为编译器无法消除
implementation()
的三个实现之间的歧义。您正在重写 MultiplyInheritedClass 中的该方法,该方法实际上重写了 FirstConcreteClass::implementation 和 SecondConcreteClass::implementation (一旦虚拟,始终虚拟)。但是,这两个虚拟调用仍然存在于 MultiplyInheritedClass 的接口中,这使得调用在调用点变得不明确。您的示例在没有虚拟继承的情况下工作的原因是公共基类的实现不存在冲突。换句话说:
因为您的示例具有所有纯虚函数,所以编译器不需要消除歧义的多个实现。因此,只有一种实现存在,并且调用是明确的。
Your first example fails because the compiler cannot disambiguate between the three implementations of
implementation()
. You are overriding that method inMultiplyInheritedClass
, which actually overrides bothFirstConcreteClass::implementation
andSecondConcreteClass::implementation
(once virtual, always virtual). However, both virtual calls still exist in the interface ofMultiplyInheritedClass
, which makes the call ambiguous at the call site.The reason that your example works without
virtual
inheritance is that there is no conflicting implementation of the common base class. Put another way:Because your example has all pure virtual functions, there's no multiple implementations which the compiler needs to disambiguate. Therefore, only one implementation exists, and the call is unambiguous.
我尝试了这两个问题代码,它们在实例化多继承类的对象时工作得很好。它不仅仅适用于多态性,例如:
原因很清楚:它不知道应该链接到抽象基类的哪个副本(抱歉表达式不好,我理解这个想法,但不能'表达出来)。而且由于虚拟继承使得派生类中只存在一份副本,所以没关系。
而且Billy ONeal的代码根本不清楚,我们应该用什么来代替注释呢?
如果我们放置:
它工作得很好,因为没有虚拟性。
我使用 Visual Studio 2008。
I tried both of the question codes and they worked fine when instantiating an object of the multi-inherited class. It didn't work only with polymorphism, like this for example:
And the reason is clear: it doesn't know to which copy of the Abstract base class it should be linked (sorry for bad expressions, I understand the idea but can't express it). And since inherting virtaully makes only one copy exist in the derived class, then it's fine.
Also the code of Billy ONeal is not clear at all, what should we place instead of the comments?
If we place:
it works fine, because of no virtuality.
I work on Visual Studio 2008.
为什么不这样做(在 中建议Benjamin Supnik 的博客文章):
其中给出:
这样:
MultiplyInheritedClass
歧义Why not do it like this (suggested in Benjamin Supnik's blog entry):
which gives:
This way:
MultiplyInheritedClass