static_cast<type>(expression)
是通用的转换形式。可以用于如 int
到 float
的转换,void*
到其它类型指针的转换。也可用于指向基类和派生类的指针之间的转换。
int i = 10;
float f = static_cast<float>(i); // int 转换为 float
void* pv = &i;
int* pi = static_cast<int*>(pv); // void* 转换为 int* 类型指针
父类指针可以指向父类对象或子类对象,子类指针不能指向父类对象。这是因为子类对象的内存占用往往大于父类对象,因为子类可能会增加额外的数据成员。
当一个子类对象被赋值给一个父类引用或指针时,这被称为向上转型。当父类指针指向子类对象时,它只能“看到”和操作该对象的父类部分。当试图将父类的指针转型为子类的指针时,这被称为向下转型。向下转型则需要谨慎,如果一个父类指针确实指向了一个子类对象,向下转型是安全的。但如果父类指针仅仅指向一个父类对象,尝试将其转换为子类指针并访问子类特定的成员会导致未定义的行为。所以我们需要使用 dynamic_cast
来进行安全检查。
dynamic_cast<type>(expression)
用于多态类型的安全向下转型。也就是说,它用于将基类的指针或引用转换为派生类的指针或引用,但要求基类至少有一个虚函数。如果转换失败(例如,尝试将基类对象的指针转换为并非实际派生类的派生类指针),dynamic_cast
会返回 nullptr
。对于引用的错误,dynamic_cast
会抛出一个 std::bad_cast
异常。例如:
#include <iostream>
class Base {
public:
virtual void foo() {
std::cout << "Base's foo()" << std::endl;
}
};
class Derived : public Base {
public:
void foo() override {
std::cout << "Derived's foo()" << std::endl;
}
void bar() {
std::cout << "Derived's bar()" << std::endl;
}
};
int main() {
// 创建一个 Derived 对象
Derived d;
// 向上转型: 将 Derived 对象当做 Base 对象使用
Base* ptrBase = &d; // 这里进行了向上转型
ptrBase->foo(); // 输出 "Derived's foo()"
// 创建一个真正的 Base 对象
Base b;
b.foo(); // 输出 "Base's foo()"
// 向下转型: 尝试将 Base 指针转回 Derived 指针
Derived* ptrDerived = dynamic_cast<Derived*>(ptrBase);
if (ptrDerived) {
ptrDerived->bar(); // 输出 "Derived's bar()"
}
// 尝试错误的向下转型: 使用真正的 Base 对象
Derived* wrongDerived = dynamic_cast<Derived*>(&b);
if (wrongDerived) {
wrongDerived->bar(); // 这里不会被执行
} else {
std::cout << "Wrong downcasting failed!" << std::endl; // 输出 "Wrong downcasting failed!"
}
return 0;
}
输出:
Derived's foo()
Base's foo()
Derived's bar()
Wrong downcasting failed!
const_cast<type>(expression)
用于删去 const
性质,从而允许修改变量的值。而如果对象是一个常量,使用 const_cast
执行写操作会产生未定义的后果。
const int ci = 10;
int* modifiable = const_cast<int*>(&ci); // 移除 const 属性
reinterpret_cast<type>(expression)
在机器和位层次上,重新解释运算对象。例如,可以将一个指针转换为另一个完全不同类型的指针,或者将指针转换为整型。
long l = 0x12345678;
char* cp = reinterpret_cast<char*>(&l); // 将 long* 转换为 char*