我注意到,如果我在下面的代码中使用 C 风格转换(或 reinterpret_cast),我会收到段错误异常,但如果我使用 dynamic_cast
,那就没问题了。为什么是这样?因为我确定指针 a 是 B 类型,因为 Add
方法已经确保输入是 B 类型。
即使我已经通过我的实现保证指针 a 的类型为 B,我是否必须在此处使用 dynamic_cast
?
编辑:
我确实意识到使用 C 风格转换(或reinterpret_cast)通常是一种不好的做法。但对于这种特殊情况,为什么它们不起作用。
这在实践中有应用,因为如果类 B 是一个接口(interface),而类 D 由于某种原因被迫存储类型 A 指针。当实现已经保证接口(interface)类型的类型安全时,这里强制使用动态强制转换。
#include <iostream>
using namespace std;
class A
{
public:
virtual ~A() = default;
};
class B
{
public:
virtual string F() = 0;
};
class C : public A, public B
{
public:
virtual ~C() = default;
virtual string F() { return "C";}
};
class D
{
public:
D() : a(nullptr) {}
void Add(B* b)
{
A* obj = dynamic_cast<A*>(b);
if(obj != nullptr)
a = obj;
}
B* Get()
{
return (B*)(a); // IF I USE DYNAMIC CAST HERE, IT'D BE OK
}
private:
A* a;
};
int main()
{
D d;
d.Add(new C());
B* b = d.Get();
if(b != nullptr)
cout << b->F();
}
最佳答案
tl;dr:c 风格的转换很狡猾,很容易引入错误。
那么这个表达式中发生了什么?
class A
{
public:
virtual ~A() = default;
};
class B
{
public:
virtual string F() = 0;
};
B* Get()
{
return (B*)(a);
}
请注意,A
和 B
不相关。
如果您使用正确的 static_cast
会怎样?
B* Get()
{
return static_cast<B*>(a);
}
然后您将看到正确的诊断:
error: invalid 'static_cast' from type 'A*' to type 'B*' return static_cast<B*>(a); ^~~~~~~~~~~~~~~~~~
哦不。
事实上,当静态转换无法完成时,c 风格会使用 reinterpret_cast
进行回退。所以你的代码相当于:
B* Get()
{
return reinterpret_cast<B*>(a);
}
这不是你想要的。这不是您要找的 Actor 。
A
子对象的地址与 B
子对象不同,主要是为了给 vtable 腾出空间。
What exactly is
reinterpret_cast
doing here?
确实不多。它只是告诉编译器将发送给它的内存地址解释为另一种类型。仅当您要求的类型在该地址具有生命周期时,它才有效。在您的情况下,情况并非如此,该位置有一个 A
对象,对象的 B
部分位于内存中的其他位置。
静态转换将调整指针以确保它指向该类型在内存中的正确偏移量,如果无法计算偏移量,则无法编译。
C* c = new C();
cout << c;
cout << "\n";
A* a = dynamic_cast<A*>(c);
cout << a;
cout << "\n";
B* b = dynamic_cast<B*>(c);
cout << b;
cout << "\n";
会给你类似的东西:
0xbe3c20
0xbe3c20
0xbe3c28
那你能做什么?
如果您想使用静态转换,则必须通过 C
,因为它是编译器可以看到 A
和 之间关系的唯一位置B
:
B* Get()
{
return static_cast<B*>(static_cast<C*>(a));
}
或者,如果您不知道 C
是否是 a
所指向的对象的运行时类型,则必须使用 dynamic_cast
.
关于c++ - 为什么我必须在这里使用dynamic_cast,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60119947/