在 C++ 中,什么是虚拟基类?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21558/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
In C++, what is a virtual base class?
提问by popopome
I want to know what a "virtual base class" is and what it means.
我想知道什么是“虚拟基类”以及它的含义。
Let me show an example:
让我举个例子:
class Foo
{
public:
void DoSomething() { /* ... */ }
};
class Bar : public virtual Foo
{
public:
void DoSpecific() { /* ... */ }
};
回答by OJ.
Virtual base classes, used in virtual inheritance, is a way of preventing multiple "instances" of a given class appearing in an inheritance hierarchy when using multiple inheritance.
在虚拟继承中使用的虚拟基类是一种在使用多重继承时防止给定类的多个“实例”出现在继承层次结构中的方法。
Consider the following scenario:
考虑以下场景:
class A { public: void Foo() {} };
class B : public A {};
class C : public A {};
class D : public B, public C {};
The above class hierarchy results in the "dreaded diamond" which looks like this:
上面的类层次结构导致“可怕的菱形”看起来像这样:
A
/ \
B C
\ /
D
An instance of D will be made up of B, which includes A, and C which also includes A. So you have two "instances" (for want of a better expression) of A.
D 的实例将由包含 A 的 B 和也包含 A 的 C 组成。 所以你有两个 A 的“实例”(为了更好的表达)。
When you have this scenario, you have the possibility of ambiguity. What happens when you do this:
当您遇到这种情况时,您就有可能产生歧义。当你这样做时会发生什么:
D d;
d.Foo(); // is this B's Foo() or C's Foo() ??
Virtual inheritance is there to solve this problem. When you specify virtual when inheriting your classes, you're telling the compiler that you only want a single instance.
虚拟继承就是为了解决这个问题。当您在继承类时指定 virtual 时,您是在告诉编译器您只需要一个实例。
class A { public: void Foo() {} };
class B : public virtual A {};
class C : public virtual A {};
class D : public B, public C {};
This means that there is only one "instance" of A included in the hierarchy. Hence
这意味着层次结构中只包含 A 的一个“实例”。因此
D d;
d.Foo(); // no longer ambiguous
This is a mini summary. For more information, have a read of thisand this. A good example is also available here.
回答by paercebal
About the memory layout
关于内存布局
As a side note, the problem with the Dreaded Diamond is that the base class is present multiple times. So with regular inheritance, you believe you have:
附带说明一下,Dreaded Diamond 的问题在于基类多次出现。因此,通过常规继承,您相信您拥有:
A
/ \
B C
\ /
D
But in the memory layout, you have:
但是在内存布局中,您有:
A A
| |
B C
\ /
D
This explain why when call D::foo()
, you have an ambiguity problem. But the realproblem comes when you want to use a member variable of A
. For example, let's say we have:
这解释了为什么调用时D::foo()
会出现歧义问题。但真正的问题是当你想使用A
. 例如,假设我们有:
class A
{
public :
foo() ;
int m_iValue ;
} ;
When you'll try to access m_iValue
from D
, the compiler will protest, because in the hierarchy, it'll see two m_iValue
, not one. And if you modify one, say, B::m_iValue
(that is the A::m_iValue
parent of B
), C::m_iValue
won't be modified (that is the A::m_iValue
parent of C
).
当您尝试访问m_iValue
from 时D
,编译器会提出异议,因为在层次结构中,它会看到两个m_iValue
,而不是一个。并且如果您修改一个,例如,B::m_iValue
(即 的A::m_iValue
父级B
),C::m_iValue
将不会被修改(即 的A::m_iValue
父级C
)。
This is where virtual inheritance comes handy, as with it, you'll get back to a true diamond layout, with not only one foo()
method only, but also one and only one m_iValue
.
这是虚拟继承派上用场的地方,因为有了它,您将回到真正的菱形布局,不仅只有一种foo()
方法,而且只有一种m_iValue
。
What could go wrong?
什么可能出错?
Imagine:
想象:
A
has some basic feature.B
adds to it some kind of cool array of data (for example)C
adds to it some cool feature like an observer pattern (for example, onm_iValue
).D
inherits fromB
andC
, and thus fromA
.
A
有一些基本特征。B
添加一些很酷的数据数组(例如)C
添加了一些很酷的功能,比如观察者模式(例如, onm_iValue
)。D
继承自B
andC
,因此继承自A
.
With normal inheritance, modifying m_iValue
from D
is ambiguous and this must be resolved. Even if it is, there are two m_iValues
inside D
, so you'd better remember that and update the two at the same time.
对于普通继承,修改m_iValue
fromD
是不明确的,必须解决这个问题。即使是这样,有两个m_iValues
里面D
,所以你最好记住,并在同一时间更新这两个。
With virtual inheritance, modifying m_iValue
from D
is ok... But... Let's say that you have D
. Through its C
interface, you attached an observer. And through its B
interface, you update the cool array, which has the side effect of directly changing m_iValue
...
使用虚拟继承,修改m_iValue
fromD
是可以的......但是......假设你有D
. 通过它的C
界面,您附加了一个观察者。并且通过它的B
接口,你更新了cool array,它的副作用是直接改变m_iValue
...
As the change of m_iValue
is done directly (without using a virtual accessor method), the observer "listening" through C
won't be called, because the code implementing the listening is in C
, and B
doesn't know about it...
由于m_iValue
直接完成了 的更改(不使用虚拟访问器方法),因此C
不会调用观察者“侦听” ,因为实现侦听的代码在 中C
,并且B
不知道...
Conclusion
结论
If you're having a diamond in your hierarchy, it means that you have 95% probability to have done something wrong with said hierarchy.
如果您的层级中有菱形,则意味着您有 95% 的可能性在该层级中做错了事。
回答by lenkite
Explaining multiple-inheritance with virtual bases requires a knowledge of the C++ object model. And explaining the topic clearly is best done in an article and not in a comment box.
用虚基解释多重继承需要了解 C++ 对象模型。最好在文章中而不是在评论框中清楚地解释主题。
The best, readable explanation I found that solved all my doubts on this subject was this article: http://www.phpcompiler.org/articles/virtualinheritance.html
我发现解决了我对这个主题的所有疑问的最好的、可读的解释是这篇文章:http: //www.phpcompiler.org/articles/virtualinheritance.html
You really won't need to read anything else on the topic (unless you are a compiler writer) after reading that...
阅读完之后,您真的不需要阅读有关该主题的任何其他内容(除非您是编译器编写者)...
回答by wilhelmtell
A virtual base class is a class that cannot be instantiated : you cannot create direct object out of it.
虚拟基类是无法实例化的类:您不能从中创建直接对象。
I think you are confusing two very different things. Virtual inheritance is not the same thing as an abstract class. Virtual inheritance modifies the behaviour of function calls; sometimes it resolves function calls that otherwise would be ambiguous, sometimes it defers function call handling to a class other than that one would expect in a non-virtual inheritance.
我认为你混淆了两个非常不同的东西。虚拟继承与抽象类不同。虚继承修改函数调用的行为;有时它会解决否则会产生歧义的函数调用,有时它会将函数调用处理推迟到非虚拟继承中所期望的类之外。
回答by wilhelmtell
I'd like to add to OJ's kind clarifications.
我想补充 OJ 的善意澄清。
Virtual inheritance doesn't come without a price. Like with all things virtual, you get a performance hit. There is a way around this performance hit that is possibly less elegant.
虚拟继承不是没有代价的。与所有虚拟事物一样,您的性能也会受到影响。有一种方法可以解决这种性能下降,但可能不太优雅。
Instead of breaking the diamond by deriving virtually, you can add another layer to the diamond, to get something like this:
您可以为钻石添加另一层,而不是通过虚拟推导来破坏钻石,以获得如下所示的内容:
B
/ \
D11 D12
| |
D21 D22
\ /
DD
None of the classes inherit virtually, all inherit publicly. Classes D21 and D22 will then hide virtual function f() which is ambiguous for DD, perhaps by declaring the function private. They'd each define a wrapper function, f1() and f2() respectively, each calling class-local (private) f(), thus resolving conflicts. Class DD calls f1() if it wants D11::f() and f2() if it wants D12::f(). If you define the wrappers inline you'll probably get about zero overhead.
没有一个类是虚拟继承的,都是公开继承的。然后类 D21 和 D22 将隐藏对 DD 不明确的虚拟函数 f(),也许通过声明函数私有。他们各自定义了一个包装函数,分别是 f1() 和 f2(),每个函数都调用类本地(私有)f(),从而解决冲突。DD 类调用 f1() 如果它需要 D11::f() 和 f2() 如果它需要 D12::f()。如果您内联定义包装器,您可能会得到零开销。
Of course, if you can change D11 and D12 then you can do the same trick inside these classes, but often that is not the case.
当然,如果您可以更改 D11 和 D12,那么您可以在这些类中执行相同的技巧,但通常情况并非如此。
回答by Luc Hermitte
In addition to what has already been said about multiple and virtual inheritance(s), there is a very interesting article on Dr Dobb's Journal: Multiple Inheritance Considered Useful
除了已经说过的关于多重继承和虚拟继承的内容之外,Dobb 博士的期刊上还有一篇非常有趣的文章:多重继承被认为是有用的
回答by wilhelmtell
It means a call to a virtual function will be forwarded to the "right" class.
这意味着对虚函数的调用将被转发到“正确的”类。
C++ FAQ LiteFTW.
C++ FAQ LiteFTW。
In short, it is often used in multiple-inheritance scenarios, where a "diamond" hierarchy is formed. Virtual inheritance will then break the ambiguity created in the bottom class, when you call function in that class and the function needs to be resolved to either class D1 or D2 above that bottom class. See the FAQ itemfor a diagram and details.
简而言之,它通常用于多继承场景,其中形成“菱形”层次结构。当您在该类中调用函数并且该函数需要解析为该底层类之上的类 D1 或 D2 时,虚拟继承将打破在底层类中创建的歧义。有关图表和详细信息,请参阅常见问题解答项目。
It is also used in sister delegation, a powerful feature (though not for the faint of heart). See thisFAQ.
它也用于姐妹委托,一个强大的功能(虽然不适合胆小的人)。请参阅此常见问题解答。
Also see Item 40 in Effective C++ 3rd edition (43 in 2nd edition).
另请参阅 Effective C++ 3rd edition 中的 Item 40(2nd edition 中的 43)。
回答by Baltimark
You're being a little confusing. I dont' know if you're mixing up some concepts.
你有点糊涂了。我不知道你是否混淆了一些概念。
You don't have a virtual base class in your OP. You just have a base class.
您的 OP 中没有虚拟基类。你只有一个基类。
You did virtual inheritance. This is usually used in multiple inheritance so that multiple derived classes use the members of the base class without reproducing them.
你做了虚拟继承。这通常用于多重继承,以便多个派生类使用基类的成员而不复制它们。
A base class with a pure virtual function is not be instantiated. this requires the syntax that Paul gets at. It is typically used so that derived classes must define those functions.
具有纯虚函数的基类不会被实例化。这需要 Paul 掌握的语法。它通常用于派生类必须定义这些函数。
I don't want to explain any more about this because I don't totally get what you're asking.
我不想对此进行更多解释,因为我不完全明白你在问什么。
回答by bradtgmurray
Virtual classes are notthe same as virtual inheritance. Virtual classes you cannot instantiate, virtual inheritance is something else entirely.
虚拟类是不一样的虚拟继承。您无法实例化的虚拟类,虚拟继承完全是另一回事。
Wikipedia describes it better than I can. http://en.wikipedia.org/wiki/Virtual_inheritance
维基百科比我能更好地描述它。http://en.wikipedia.org/wiki/Virtual_inheritance