简体   繁体   English

什么可以导致C ++中的纯虚函数调用?

[英]What can cause a pure virtual function call in C++?

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. 我教了一个C ++编程类,我已经看到了足够多的错误类型,我对如何诊断常见的C ++错误感觉很好。 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? 在帮助调试学生代码时,还有其他我应该注意的事项吗?

"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 (eg 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. 在销毁之后,通过“悬空”指针或引用继续使用对象可以调用纯虚函数,但在这种情况下没有定义的行为。

Here are a few cases in which a pure virtual call can happen. 以下是一些纯虚拟调用可能发生的情况。

  1. 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 使用悬空指针 - 指针不是有效对象,因此它指向的虚拟表只是随机内存,可能包含NULL
  2. Bad cast using 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 is a virtual table unlike the previous option). 坏铸件 static_cast了错误的类型(或C样式转换),还可以使你指向不具有在其虚表的正确方法(在这种情况下,对象至少它确实不同于以往的选项的虚拟表)。
  3. 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 已卸载DLL - 如果您要保留的对象是在已再次卸载的共享对象文件(DLL,so,sl)中创建的,则内存现在可以清零

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. 例如,当对象的引用或指针指向NULL位置,并且您使用对象引用或指针来调用类中的虚函数时,就会发生这种情况。 For example: 例如:

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. 此时,存储在objContainer [0]中的对象不存在。 When the virtual table is indexed, no valid memory location is found. 索引虚拟表时,找不到有效的内存位置。 Hence, a run time error is issued saying "pure virtual function called". 因此,发出运行时错误,称“称为纯虚函数”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM