c++ - static_cast 安全

标签 c++ casting static-cast

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_castvoid* 做不安全的事情。

关于c++ - static_cast 安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2382054/

相关文章:

c++ - 为什么 std::string 即使在删除后也会导致类中的内存泄漏

c++ - 平凡的函数给出了意想不到的返回值

c++ - friend std::ostream& operator<< 声明不允许我访问类的私有(private)成员

c++ - 如果 int 是 "not within the enums range",为什么将其转换为强类型枚举会编译?

从 double 到 const int 的 C++ 类型转换不能正常工作

c++ - 将 Derived*const 转换为 Base*const

c++ - 使用友元类访问私有(private)数据成员

mysql - 如何从 MySql 列中删除或转换非 UTF 8/UTF-8 字符

c - 来自 int 的基本 C 强制转换警告指针

c++ - static_cast 的神秘行为