说一说c++中四种cast转换
const_cast
可以消去变量类型中的const
和volatile
。可以利用它来改const
变量的值,但是修改const
变量是未定义行为,不要这么做。static_cast
是静态类型转换,一般代码中用得最多的就是它,可以用来转换常量类型,或者子类指针/引用转父类。C++里void*
转T*
就要用它(C++禁止void*
隐式转换为其他类型指针,反之可以。C语言二者都允许)reinterpret_cast
是在二进制层面上将值按照新类型重新解释,比方说查看指针地址的整数值就用cout << reinterpret_cast<std::uintptr_t>(some_ptr)
,又或者想直接操纵浮点数的二进制就用reinterpret_cast<std::int32_t&>(some_float)
。它非常危险,少用dynamic_cast
使用了RTTI来做类型检查,父类转子类的时候使用它更安全。如果是不能转换的类型,转引用会抛std::bad_cast
异常,转指针会返回nullptr
。用得非常少,因为一用就会引入RTTI,造成代码膨胀。而且需要根据实际类型作出行动可以抽象成虚函数,不需要cast。
int a = 10; float b = static_cast<float>(a);
在这个例子中,static_cast将int类型的变量a转换为float类型并赋值给b。这种转换是比较安全的,因为从int到float的转换在数值表示上是合理的,只是数据精度可能会发生变化。
class Base {}; class Derived : public Base {}; Derived d; Base* b = static_cast<Base*>(&d);
这里将派生类Derived的对象d的地址转换为基类Base的指针b。这是一种向上转型,在类层次结构中是安全的,因为派生类对象通常包含了基类对象的所有属性和行为。
class Base {}; class Derived : public Base {}; Base b; Derived* d = static_cast<Derived*>(&b);
这里试图将基类Base对象的地址转换为派生类Derived的指针,这是不安全的,因为基类对象可能不包含派生类特有的成员,这种转换可能会导致访问非法内存区域等问题。
class Base { virtual void func() {} }; class Derived : public Base {}; Base* b = new Derived(); Derived* d = dynamic_cast<Derived*>(b); if (d!= nullptr) { // 转换成功,说明b指向的对象实际上是Derived类型或者其派生类型 }
在这个例子中,首先创建了一个Derived类的对象,并通过基类指针b来指向它。然后使用dynamic_cast将基类指针b转换为派生类指针d。如果b指向的对象确实是Derived类型或者其派生类型,那么d将不为nullptr,表示转换成功;否则,d将为nullptr,表示转换失败。
void func(const int* p) { int* nonConstP = const_cast<int*>(p); *nonConstP = 10; } int main() { const int a = 5; func(&a); return 0; }
在这个例子中,函数func接收一个const指针p,然后使用const_cast将其转换为非const指针nonConstP,并修改了指针所指向的值。不过这种做法可能会导致未定义行为,因为a是一个真正的const变量,修改它违反了const的语义。正确的做法是只有当对象本身在定义时没有被真正的const语义所限制时,才可以使用const_cast来合理地修改对象。
int a = 10; char* p = reinterpret_cast<char*>(&a);
在这个例子中,reinterpret_cast将int类型变量a的地址转换为char类型的指针p。这种转换后的指针操作需要非常小心,因为它可能会导致访问非法内存区域或者错误地解释数据。例如,使用p来访问内存就好像内存中存储的是char类型的数据,而实际上它原本是int类型的数据。