我有如下小程序:
#include <iostream>
#include <map>
using namespace std;
class A {
public:
virtual void hello(int i)
{
cout << "A Hello " << i << endl;
};
};
class B {
public:
virtual void nothing() = 0;
};
class C : public A, public B {
public:
virtual void hello(int i) override
{
cout << "C Hello " << i << endl;
};
virtual void nothing() override
{
cout << "C Nothing " << endl;
}
};
int main() {
map<int, B*> map_;
A* testA = new C();
map_[0] = (B*)testA;
B* myB = static_cast<B*>(map_[0]);
myB->nothing();
C* testC = new C();
map_[1] = (B*)testC;
myB = static_cast<B*>(map_[1]);
myB->nothing();
return 0;
}
作为输出,我期待以下内容:
C Nothing
C Nothing
但这是我得到的:
C Hello 0
C Nothing
因此调用了错误的函数:hello(int i) 被调用,即使它从未在代码中被调用。我知道这与类型转换有关,但我不明白错误在哪里。
为什么调用 hello(int i)?
最佳答案
基类指针之间的转换(有时称为交叉转换)需要dynamic_cast
。给定一个指向 A
的指针,没有办法(静态地)知道它是 C
对象的一部分,因此也没有办法静态地找到相应的 B
子对象。
您所谓的“常规”类型转换是最危险的类型转换类型。你永远不应该使用那种类型的转换(至少,不要转换指针或引用)。它将强制使用它可以使用的任何强制转换 - 除了 dynamic_cast
。所以在这种情况下,它相当于 reinterpret_cast
,假装在与 A
对象相同的地址处有一个 B
对象。由于那里没有 B
(它在 C
中的其他地方),您会得到未定义的行为。
(具体的风格或未定义的行为可能是它使用了在 B
中包含 nothing
的虚拟表条目,但实际上包含 hello
,所以最终以一些未定义的值作为参数调用它。但是当然,由于未定义,原则上任何事情都可能发生。)
关于c++ - 常规转换的内存损坏?调用了错误的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25619041/