什么会导致 C++ 中的纯虚函数调用?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4612702/
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
What can cause a pure virtual function call in C++?
提问by templatetypedef
I teach a C++ programming class and I've seen enough classes of errors that I have a good feeling for how to diagnose common C++ bugs. However, there's one major type of error for which my intuition isn't particularly good: what programming errors cause calls to pure virtual functions?The most common error I've seen that causes this is calling a virtual function from a base class constructor or destructor. Are there any others I should be aware of when helping debug student code?
我教过一门 C++ 编程课,我已经看到了足够多的错误类别,我对如何诊断常见的 C++ 错误有很好的感觉。但是,有一种主要类型的错误我的直觉不是特别好:哪些编程错误会导致调用纯虚函数?我见过的最常见的错误是从基类构造函数或析构函数调用虚函数。在帮助调试学生代码时,还有其他我应该注意的吗?
采纳答案by Tony Delroy
"The most common error I've seen that causes this is calling a virtual function from a base class constructor or destructor."
“我见过的最常见的错误是从基类构造函数或析构函数调用虚函数。”
When an object is constructed, the pointer to the virtual dispatch table is initially aimed at the highest superclass, and it's only updated as the intermediate classes complete construction. So, you can accidentally call the pure virtual implementation up until the point that a subclass - with its own overriding function implementation - completes construction. That might be the most-derived subclass, or anywhere in between.
构造对象时,指向虚拟调度表的指针最初指向最高超类,并且仅在中间类完成构造时才更新。因此,您可能会意外地调用纯虚拟实现,直到子类(具有自己的覆盖函数实现)完成构造为止。那可能是派生最多的子类,或者介于两者之间。
It might happen if you follow a pointer to a partially constructed object (e.g. in a race condition due to async or threaded operations).
如果您遵循指向部分构造对象的指针(例如,由于异步或线程操作而导致的竞争条件),则可能会发生这种情况。
If a compiler has reason to think it knows the real type to which a pointer-to-base-class points, it may reasonably bypass the virtual dispatch. You might confuse it by doing something with undefined behaviour like a reinterpret cast.
如果编译器有理由认为它知道基类指针指向的真实类型,它可以合理地绕过虚拟分派。您可能会通过执行一些未定义的行为(例如重新解释强制转换)来混淆它。
During destruction, the virtual dispatch table should be reverted as derived classes are destroyed, so the pure virtual implementation may again be invoked.
在销毁过程中,当派生类被销毁时,虚拟调度表应该被恢复,这样纯虚拟实现可能会再次被调用。
After destruction, continued use of the object via "dangling" pointers or references may invoke the pure virtual function, but there's no defined behaviour in such situations.
销毁后,通过“悬空”指针或引用继续使用对象可能会调用纯虚函数,但在这种情况下没有定义的行为。
回答by Motti
Here are a few cases in which a pure virtual call can happen.
以下是可能发生纯虚拟调用的几种情况。
- Using a dangling pointer- the pointer isn't of a valid object so the virtual table it points to is just random memory which may contain NULL
- Bad castusing a
static_cast
to the wrong type (or C-style cast) can also cause the object you point to to not have the correct methods in its virtual table (in this case at least it really isa virtual table unlike the previous option). - DLL has been unloaded- If the object you're holding on to was created in a shared object file (DLL, so, sl) which has been unloaded again the memory can be zeroed out now
- 使用悬空指针- 指针不是有效对象,因此它指向的虚拟表只是可能包含 NULL 的随机内存
- 坏投用
static_cast
了错误的类型(或C样式转换),还可以使你指向不具有在其虚表的正确方法(在这种情况下,至少它真正的对象是不同于以往的选项的虚拟表) . - DLL 已卸载- 如果您持有的对象是在已再次卸载的共享对象文件(DLL、so、sl)中创建的,则现在可以将内存清零
回答by cppcoder
This can happen for example when the reference or pointer to an object is pointing to a NULL location, and you use the object reference or pointer to call a virtual function in the class. For example:
例如,当指向对象的引用或指针指向 NULL 位置,并且您使用对象引用或指针调用类中的虚函数时,就会发生这种情况。例如:
std::vector <DerivedClass> objContainer;
if (!objContainer.empty())
const BaseClass& objRef = objContainer.front();
// Do some processing using objRef and then you erase the first
// element of objContainer
objContainer.erase(objContainer.begin());
const std::string& name = objRef.name();
// -> (name() is a pure virtual function in base class,
// which has been implemented in DerivedClass).
At this point object stored in objContainer[0] does not exist. When the virtual table is indexed, no valid memory location is found. Hence, a run time error is issued saying "pure virtual function called".
此时存储在 objContainer[0] 中的对象不存在。索引虚拟表时,找不到有效的内存位置。因此,会发出一个运行时错误,说“调用了纯虚函数”。