c++ - 常规转换的内存损坏?调用了错误的函数

标签 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;
}

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

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/

相关文章:

scala - 涉及 mutable.IndexedSeq、view、take 和 grouped 的集合代码会抛出 ClassCastException

java - 假设列表类型是 int java

c++ - C++ 中 "::delete"的用途是什么?

C++ 案例 multimap

c++ - 发送新类型作为参数

c++ - 用于遍历继承层次结构的 Static_cast 与 dynamic_cast

c++ - 带有 boost::shared_ptr 的 static_cast?

c++ - 虚函数和static_cast

python - 在 C/openCL 中寻址 vector 元素

c++ - 大无符号整数 (C++)