常规演员阵容的内存损坏?错误的功能叫

Mar*_*ard 5 c++ casting static-cast

我有以下小程序:

#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;
}
Run Code Online (Sandbox Code Playgroud)

作为输出,我期待以下内容:

C Nothing
C Nothing 
Run Code Online (Sandbox Code Playgroud)

但这是我得到的:

C Hello 0
C Nothing 
Run Code Online (Sandbox Code Playgroud)

因此调用了错误的函数:即使在代码中从未调用过hello(int i),也会调用它.我知道它与演员有关,但我无法理解错误在哪里.

为什么要调用hello(int i)?

Mik*_*our 7

基类指针之间的转换(有时称为交叉转换)需要dynamic_cast.给定一个指针,A无法(静态地)知道它是C对象的一部分,因此无法静态地找到相应的B子对象.

你称之为"常规"演员是最危险的演员阵容.你永远不应该使用那种样式的强制转换(至少不要转换指针或引用).除了之外,它会强制使用任何演员来进行转换dynamic_cast.所以在这种情况下,它等同于reinterpret_cast假装B在与对象相同的地址处存在A对象.由于那里没有B(它在其他地方C),你会得到未定义的行为.

(具体的风格或未定义的行为可能是它使用包含nothing在a B中但实际上包含的虚拟表条目,hello因此最终调用它,并以一些未定义的值作为参数.但当然,未定义,任何事情都可能原则上发生.)