AFAIK,对于指针/引用 static_cast,如果此时编译器看不到类定义,则 static_cast
的行为将类似于 reinterpret_cast
。
为什么 static_cast
对指针/引用不安全而对数值安全?
最佳答案
简而言之,因为多重继承。
长:
#include <iostream>
struct A { int a; };
struct B { int b; };
struct C : A, B { int c; };
int main() {
C c;
std::cout << "C is at : " << (void*)(&c) << "\n";
std::cout << "B is at : " << (void*)static_cast<B*>(&c) << "\n";
std::cout << "A is at : " << (void*)static_cast<A*>(&c) << "\n";
}
输出:
C is at : 0x22ccd0
B is at : 0x22ccd4
A is at : 0x22ccd0
请注意,为了正确转换为 B*,static_cast 必须更改指针值。如果编译器没有 C 的类定义,那么它就不会知道 B 是一个基类,并且肯定不知道要应用什么偏移量。
但是在没有定义可见的情况下,static_cast 的行为不像 reinterpret_cast,它是被禁止的:
struct D;
struct E;
int main() {
E *p1 = 0;
D *p2 = static_cast<D*>(p1); // doesn't compile
D *p3 = reinterpret_cast<D*>(p1); // compiles, but isn't very useful
}
一个普通的 C 风格转换,(B*)(&c)
做你说的:如果结构 C 的定义是可见的,表明 B 是一个基类,那么它是一样的作为 static_cast。如果类型仅向前声明,则它与 reinterpret_cast 相同。这是因为它被设计为与 C 兼容,这意味着它必须在 C 可能的情况下做 C 做的事情。
static_cast 总是知道为内置类型做什么,这就是内置的真正含义。它可以将 int 转换为 float,等等。所以这就是为什么它对数字类型总是安全的,但它不能转换指针,除非 (a) 它知道它们指向什么,并且 (b) 指向的类型之间存在正确的关系。因此它可以将 int
转换为 float
,但不能将 int*
转换为 float*
。
正如 AndreyT 所说,有一种方法可以不安全地使用 static_cast
,编译器可能不会救你,因为代码是合法的:
A a;
C *cp = static_cast<C*>(&a); // compiles, undefined behaviour
static_cast
可以做的一件事是“向下转换”指向派生类的指针(在这种情况下,C 是 A 的派生类)。但是,如果 referand 实际上不是派生类的,那你就完蛋了。 dynamic_cast
会在运行时执行检查,但对于我的示例类 C,您不能使用 dynamic_cast
,因为 A 没有虚函数。
您可以类似地使用 static_cast
和 void*
做不安全的事情。
关于c++ - static_cast 安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2382054/