非虚拟多重继承的示例

5
有没有一个现实世界的例子,使用了非虚拟多重继承?我想要一个主要是为了教学目的。简单地使用命名为A、B、C和D的类进行实验是完全可以的,其中B和C从A继承,而D从B和C继承。这可以用来解释问题“一个D对象应该有一个还是两个A子对象?”,但这并不能解释我们为什么需要这两个选项。许多例子都关注于为什么我们需要虚继承,但为什么我们不需要虚继承呢?
我知道什么是虚基类以及如何在代码中表达这种情况。我也知道菱形继承和具有虚基类的多重继承的例子很多。
最好的例子是车辆。基类是Vehicle,由Car和Boat继承。除其他功能外,Vehicle还具有occupants()和max_speed()。因此,同时从Car和Boat继承的Amphibian在陆地和水中继承了不同的max_speed(),这是有意义的,但它们也有不同的occupants(),这是没有意义的。所以Vehicle的子对象并不是真正独立的;这是另一个可能有趣的问题,但这不是本问题。
有没有一个现实世界的例子,使这两个子对象真正独立?

这可能比你想象中的更贴近实际,但SFML经常使用非虚拟多重继承。例如:sf::Windowsf::Spritesf::VertexBuffersf::Shape,仅举几例。 - alter_igel
一个从叶子类继承的元组实现可以多次从同一类型继承,以利用 EBO,如果同一类型出现多次。 - L. F.
2个回答

5
你的思维模式像一个OOP程序员,试图设计事物的抽象模型。C++多重继承,就像C++中的许多东西一样,是一个具有特定效果的工具。它是否映射到某个OOP模型与工具本身的效用无关。换句话说,你不需要一个“真实世界的模型”来证明非虚拟继承的合理性;你只需要一个真实的用例
因为派生类继承了基类的成员,所以继承常常被用于C++中将一组通用功能集合在一起的方式,有时候派生类与基类之间的交互很少,并将这些功能直接注入到派生类中。
奇异递归模板模式和其他类似mixin的构造方法是实现此目的的机制。其思路是:您有一个作为模板的基类,其模板参数是使用它的派生类。这使得基类可以在没有virtual函数的情况下访问到派生类本身。
我能想到的C++中最简单的例子是enable_shared_from_this,它允许当前由shared_ptr管理生命周期的对象通过指向该对象的指针/引用来获取一个指向该对象的shared_ptr。这使用CRTP将各种成员和接口添加到派生类中,以使shared_from_this成为可能。并且由于继承是公开的,它还允许shared_ptr的各种函数“启用shared_from_this”来检测特定类型是否具有其中的shared_from_this内容,并正确初始化它。 enable_shared_from_this不需要虚拟继承,事实上,它很可能无法很好地工作。
现在想象一下我有另一个使用CRTP注入某些其他功能到对象中的类。这个功能与shared_ptr没有任何关系,但它使用CRTP和继承。
那么,如果我现在编写一些想要同时继承enable_shared_from_this 这些其他功能的类型,那么这也完全可以正常工作。不需要虚拟继承,实际上这样做只会使组合更加困难。
虚拟继承不是免费的。它从根本上改变了类型与其基类之间的许多关系。如果您从这样的类型继承,您的构造函数必须直接初始化任何虚拟基类。这样的类型布局非常奇怪,不太可能标准化。还有其他各种事情。C++尝试不让程序员为他们不使用的功能付费,因此如果您不需要虚拟继承的特殊属性,就不应该使用它。

1

这也是为什么C++有非虚方法的原因--因为如果使用非虚继承,实现会更简单和高效,所以如果您想要虚继承,就需要明确地请求。由于如果您的类从未使用多重继承,则不需要虚继承,因此这是默认设置。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接