一、static_cast
static_cast 是 C++ 中的一个类型转换操作符,用于执行编译时的静态类型转换,类似于C风格转换(如(int)x)。但是比C风格转换更安全。它主要用于较为明确的类型转换,例如数值类型之间的转换,基本数据类型的指针和引用之间的转换。
当转换对象具有继承关系时,最好不要用static_cast,因为它不会做运行时类型检查。
int main() {
double d = 3.14;
int i = static_cast<int>(d); // 将double类型的d转换为int类型
return 0;
}
除此之外,static_cast也可以用于将数值、指针或引用从非const转换为const。这点和const_cast功能相反。如下:
#include <iostream>
void printValue(const int& value) {
std::cout << "Value: " << value << std::endl;
}
int main() {
int number = 10;
printValue(static_cast<const int&>(number)); // 将非 const 整数值转换为 const 引用,但其实不加static_cast也能通过编译
int value = 10;
const int* ptr = static_cast<const int*>(&value); // 将int类型的指针转换为const int类型的指针,但其实不加static_cast也能通过编译
// 此时ptr指向的对象是不可修改的,这样可以确保value不会在ptr的作用域内被修改
// *ptr = 20; // 这个会导致编译错误
return 0;
}
加了static_cast是显式转换。但其实不加static_cast也能通过编译,编译器会自动做隐式转换。
二、dynamic_cast
如果使用 dynamic_cast 将指向基类对象的指针转换为指向派生类对象的指针,而转换不安全,dynamic_cast 会返回空指针。但是如果用static_cast,则会显示都成功。所以在涉及到父类和子类对象之间的转换时,不要用static_cast,而是dynamic_cast。
以下是一个使用 dynamic_cast 进行向下转换的示例,演示了当转换失败时 dynamic_cast 返回空指针的情况:
#include <iostream>
class Base {
public:
virtual ~Base() {}
};
class Derived : public Base {
// 派生类的内容
};
int main() {
Base base_1;
// 尝试将指向基类对象的指针转换为指向派生类对象的指针
Derived* derived_1 = dynamic_cast<Derived*>(&base_1);
if (derived_1 == nullptr) {
std::cout << "base_1转换失败" << std::endl;
} else {
std::cout << "base_1转换成功" << std::endl;
}
Base* base_2 = new Derived();
Derived* derived_2 = dynamic_cast<Derived*>(base_2);
if (derived_2 == nullptr) {
std::cout << "base_2转换失败" << std::endl;
} else {
std::cout << "base_2转换成功" << std::endl;
}
}
输出是:
base_1转换失败
base_2转换成功
main.cpp: In function ‘int main()’:
main.cpp:16:56: warning: dynamic_cast of ‘Base base_1’ to ‘class Derived*’ can never succeed
16 | Derived* derived_1 = dynamic_cast<Derived*>(&base_1);
| ^
如果用static_cast,则会显示都成功。
但是dynamic_cast无法用于一般类型转换,它不能直接用于数值类型之间的转换等。所以dynamic_cast也无法完全取代static_cast。
三、const_cast
const_cast 主要用于将 const 类型对象的常量属性去除,以便能够对其进行修改。举个例子:
#include <iostream>
class MyClass {
public:
MyClass(int value) : m_value(value) {}
void modifyValue() const {
const_cast<int&>(m_value) = 20; // 去除常量性,允许修改成员变量
}
void printValue() const {
std::cout << "Value: " << m_value << std::endl;
}
private:
int m_value;
};
int main() {
const MyClass obj(10);//注意这里的const,表示对象obj是一个常量对象,只能调用const修饰的函数
obj.printValue(); // 输出 10
obj.modifyValue(); // 允许修改常量对象
obj.printValue(); // 输出 20
return 0;
}
程序输出是:
Value: 10
Value: 20
四、reinterpret_cast
reinterpret_cast可以用于执行各种不同类型指针之间的转换,甚至是指针类型和整数类型之间的转换。它的主要功能是执行底层的位模式重解释,而不进行标准的类型转换或数值转换。它也不做安全检查。例子如下:
#include <iostream>
int main() {
int number = 65;
char* charPtr = reinterpret_cast<char*>(&number);
std::cout << *charPtr << std::endl; // 输出 'A',将 int 转换为 char
return 0;
}
在这个例子中,我们使用 reinterpret_cast 将 int 类型的指针转换为 char 类型的指针,这允许我们将整数65的位模式解释为字符 ‘A’。需要注意的是,这种转换方式是非常危险的,因为 char 类型指针不一定能够准确地解释 int 类型的数据。
尽管它非常危险,但在某些情况下是必需的。比如和C代码进行交互。使用它的场景比较少,真正要用时也需要谨慎,因为它没有安全检查。
五、C风格转换(如(int)x)
它跟static_cast类似,但是static_cast更安全,它会做编译时类型检查。在写C++代码时,建议使用static_cast。
举例说明
#include <iostream>
int main() {
double d = 10.5;
int i = static_cast<int>(d); // 将 double 转换为 int,编译成功
char* ptr = static_cast<char*>(&i); // 将 int* 转换为 char*,编译报错
//char* ptr = (char*)(&i); // 将 int* 转换为 char*, 编译成功
return 0;
}
编译结果是:
main.cpp: In function ‘int main()’:
main.cpp:7:38: error: invalid static_cast from type ‘int*’ to type ‘char*’
7 | char* ptr = static_cast<char*>(&i); // 将 int* 转换为 char*,编译报错
| ^