FAQ: Why does dynamic_cast only work if a class has at least 1 virtual method?
这不能在C ++中编译:
1 2 3 4 5 6 7 8 9 10 11 12
| class A
{
};
class B : public A
{
};
...
A *a = new B();
B *b = dynamic_cast<B*>(a); |
-
我对此问题进行了常见问题解答。 答案很简短,但我认为很可靠。 如果有人认为这不是常见问题解答,请在评论中让我知道。
-
@约翰:我同意。
因为dynamic_cast只能向下转换多态类型,所以说标准。
您可以通过在基类中添加一个virtual析构函数来使您的类成为多态的。实际上,无论如何,您可能都应该这样做(请参阅脚注)。否则,如果尝试通过A指针删除B对象,则会引起未定义行为。
1 2 3 4 5
| class A
{
public:
virtual ~A() {};
}; |
等等!
脚注
对于需要多态类型的虚拟析构函数的"规则"有一些例外。
一种例外是使用boost::shared_ptr时,如Steve Jessop在下面的注释中所指出的。有关何时需要虚拟析构函数的更多信息,请阅读此Herb Sutter文章。
-
"您会泄漏资源。" ->"您会得到UB"。
-
@GMan:谢谢,编辑
-
说得通。谢谢!
-
规则50:使基类的析构函数成为公共的和虚拟的,或受保护的和非虚拟的(gotw.ca/publications/c++cs.htm)。有时您不希望多态。只是在说。
-
@gregg:确实是这样,但是OP在这里需要多态性
-
有时您需要多态性,但不需要delete来实现多态性。
-
@Steve:请举个例子吗?
-
@John:(1)如果指针直接用shared_ptr ptr(new derived)存储。 (2)如果对象的用户负责其内存管理,并通过基类使用它,而负责内存管理的人则使用派生类。基本上,您所拥有的类可能具有一些虚函数和一些非虚函数,但在这种情况下,非虚"函数"是删除它的操作。并非所有对象的所有用户都需要删除该对象作为其API的一部分。
-
@Steve:在(1)中,您仍然需要虚拟dtor。 shared_ptr将通过base *删除。 (2)是的,如果delete-er通过派生的ptr删除,则不需要虚拟析构函数。不能想到什么时候会发生,但是可以。
-
@John:在(1)中,它将通过derived*删除。检查shared_ptr的模板构造函数。 (2)取决于您的编程风格-如果对对象的任何访问总是伴随着生命周期管理,那么所有接口都必须包含delete,因此多态接口需要虚拟析构函数。如果您看到的是没有所有权的对象类型,那么即使存在虚拟功能,受保护的非虚拟析构函数也可能适用。
-
例如,您可能有一个虚拟的访问者界面,并且进行访问的循环不会删除访问者,因此delete并不是访问者界面的一部分。通常,在C ++中,您会为访问者使用模板,但并非总是如此。
-
@Steve:(1)哈哈,我不知道!有点酷。 +1为关键学习!
-
@John:UB的更好链接:stackoverflow.com/questions/2397984/
-
@sbi:这是我一直用于UB的更好的链接
-
@John:90秒搜索常见问题列表!
-
@sbi:那就是我想出我正在使用的链接的方式。不用担心,现在我正在使用新的闪亮链接。好多了
就像其他人所说的:标准是这样说的。
那么为什么标准这么说呢?
因为如果类型不是多态的,则它可能是(或是标准大师的问题)是普通类型。对于普通类型,有许多来自C向后兼容性的假设。
其中之一是,类型仅由开发人员声明的成员+必要的对齐字节组成。因此,不能有任何其他(隐藏)字段。
因此,无法在A所保存的内存空间中存储它确实是B的信息。
仅当它是多态的时才有可能,因为这样才可以添加此类隐藏的内容。
(在大多数实现中,这是通过vtable完成的)。
-
这就是著名的"不要为不使用的东西付钱"公理:如果您不需要运行时多态,就不会得到它。没有虚拟表ergo no late type RTTI ergo no dynamic_cast。
从5.2.7(动态转换):
The result of the expression
dynamic_cast< T >(v) is the result of
converting the expression v to type T.
[ ... multiple lines which refer to other cases ... ]
Otherwise v shall be a
pointer to or an lvalue of a
polymorphic type (10.3).
从10.3(虚拟功能)开始:
A class that declares or inherits a
virtual function is called a
polymorphic class.