我理解在使用多重继承时需要虚拟继承 - 它解决了可怕的钻石问题。
但是,如果我没有使用多重继承怎么办? 是否需要虚拟继承?
我似乎记得听说它对异常很重要(抛出派生类,通过基类引用捕获)。但虚拟析构函数不应该足够吗?
我已经尝试搜索我曾经看过的参考页面,但我似乎无法找到它。
答案 0 :(得分:17)
你可能正在考虑这个Boost.Exception guideline,为了完整起见,我将在这里复制:
从其他异常类型派生时,异常类型应使用虚拟继承。这种见解归功于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时,通常这个细节无关紧要。使用,因为它使异常类型成为没有成员的简单结构(没有什么可以初始化。)See Exception Types as Simple Semantic Tags。
答案 1 :(得分:1)
如果您的异常类涉及多重继承,请单击
答案 2 :(得分:1)
虚拟继承的唯一成本是vtable,这不是很大的成本。使用虚拟继承意味着在人们从各种事物继承之后,双钻石问题不会意外地支持他们丑陋的头部。这只意味着你的班级将成为一个很好的基础。
答案 3 :(得分:0)
不,除了解决钻石问题外,不需要它。你必须想象事情!
答案 4 :(得分:-1)
我理解在使用多重继承时需要虚拟继承 - 它解决了可怕的钻石问题。
但是如果我没有使用多重继承呢?
问题(主要是修辞): 你怎么知道MI永远不会被使用?
答案:你无法知道。 (直到你证明你这样做。)
我似乎记得听说它对异常很重要(抛出派生类,通过基类引用捕获)。但虚拟析构函数不应该足够吗?
问题(修辞): 为什么这里需要虚拟析构函数?
答案:事实并非如此。