我理解在使用多重继承时需要虚拟继承——它解决了可怕的钻石问题。
但是如果我不使用多重继承呢? 是否需要虚拟继承?
我似乎记得听说过它对异常很重要(抛出派生类,通过基类引用捕获)。但是虚拟析构函数不应该足够吗?
我已经尝试搜索我曾经在此看到的参考页面,但我似乎无法找到它。
我理解在使用多重继承时需要虚拟继承——它解决了可怕的钻石问题。
但是如果我不使用多重继承呢? 是否需要虚拟继承?
我似乎记得听说过它对异常很重要(抛出派生类,通过基类引用捕获)。但是虚拟析构函数不应该足够吗?
我已经尝试搜索我曾经在此看到的参考页面,但我似乎无法找到它。
您可能正在考虑这个Boost.Exception 指南,为了完整起见,我将在此处复制它:
当从其他异常类型派生时,异常类型应该使用虚拟继承。这种洞察力归功于 Andrew Koenig。使用虚拟继承可以防止异常处理程序中的歧义问题:
#include <iostream>
struct my_exc1 : std::exception { char const* what() const throw(); };
struct my_exc2 : std::exception { char const* what() const throw(); };
struct your_exc3 : my_exc1, my_exc2 {};
int
main()
{
try { throw your_exc3(); }
catch(std::exception const& e) {}
catch(...) { std::cout << "whoops!" << std::endl; }
}
上面的程序输出“哎呀!” 因为到 std::exception 的转换是模棱两可的。
在异常处理的上下文中,虚拟继承引入的开销总是可以忽略不计。请注意,虚拟基由最派生类型的构造函数直接初始化(在异常情况下传递给 throw 语句的类型)。但是,通常在使用 boost:: exception时不需要考虑这个细节,因为它使异常类型成为没有成员的普通结构(无需初始化)。请参阅 Exception Types as Simple Semantic Tags。
是的,如果您的异常类涉及多重继承。
虚拟继承的唯一成本是 vtable,它的成本并不高。使用虚拟继承意味着人们在继承了各种东西之后,双菱形问题就不会意外地抬头了。这只是意味着你的类将成为一个很好的基类。
不,除了解决钻石问题之外不需要它。你一定是在想象事情!
我理解在使用多重继承时需要虚拟继承——它解决了可怕的钻石问题。
但是如果我不使用多重继承呢?
问题(主要是修辞):你怎么知道 MI 永远不会被使用?
答:你不能知道。(直到你证明你做到了。)
我似乎记得听说过它对异常很重要(抛出派生类,通过基类引用捕获)。但是虚拟析构函数不应该足够吗?
问题(修辞):为什么这里需要一个虚拟析构函数?
答:不是。