C++:编译对无关派生类、bug或特性的函数调用

C++: compiling function call to unrelated derived class, bug or feature?

本文关键字:bug 函数调用 编译 派生 C++      更新时间:2023-10-16

在C++中闲逛时,我偶然发现了一些我认为是clang++(6.0(和g++(5.3(错误的东西:我能够欺骗编译器调用它不应该调用的函数。

简而言之,我声明了一个抽象基类,从中派生出两个类:非抽象类和抽象类,它们仅通过它们的公共基类相关,但具有不同的功能。实例化非抽象基类,并诱使编译器创建一个指向非派生类的抽象派生类指针,我可以通过该指针调用原始非抽象类和抽象类的函数。

最简单的例子是,让我头疼的两行在底部,中间有一条带星号的评论行:

#include <cassert>
#include <iostream>
#include <typeinfo>
class MYBase {
public:
virtual void fun1() = 0;
};
class MYDer1 : public MYBase {
public:
~MYDer1() { std::cout << "~MYDer1()n"; }
void fun1() { std::cout << "MYDer1 fun1n"; }
};
class MYDer2 : public MYBase {
public:
~MYDer2() { std::cout << "~MYDer2()n"; }
void something2() { std::cout << "MYDer2 something2n"; }
};

int main () {
MYDer1 x1;
// Good: cannot instantiate a 'MYDer2' as it is an abstract class
//  due to unimplemented pure virtual method 'fun1' in 'MYDer2'
//
// MYDer2 x2;
// Good, clang++ and g++ rightfully refuse to compile this:
//
//   auto * pd2 = static_cast<MYDer2 *>(&x1);
// So let's be 'clever' and take a detour via 'void':
auto * pd2 = static_cast<MYDer2 *>(static_cast<void *>(&x1));
// Just to be sure the compiler got it right
assert(typeid(pd2) == typeid(MYDer2 *));
/***********************************************************/
// There is no "fun1" declared in MYDer2
// So why does this even compile?
pd2->fun1();
// And why does this execute correctly?
pd2->something2();
return 0;
}

我错过了什么?

这是一种未定义的行为,所以这次你射中了自己的腿,但没有打中。程序员有责任确保被取消引用的指针真正指向指定类型的对象。

这是未定义的行为,因为x1的类型为MYDer1,并且您强制将其强制转换为MYDer2。代码可能不起作用,因为您并没有真正使用函数something2执行任何操作。尝试向MYDer2添加一个成员变量并打印它以查看问题。