C++转型操作符是一种用于在不同类型之间进行转换的运算符,它们可以提供更安全、更明确、更易于识别的转换方式,以替代C语言中的旧式转型。C++提供了四种转型操作符,分别是:
static_cast
:用于基本类型之间的转换,或者类层次间的上行转换(从派生类到基类),或者无关类之间的转换(需要用户自定义转换函数)。它是最常用的转型操作符,但是不能用于去除常量性或执行运行时类型检查。const_cast
:用于改变表达式的常量性或易变性,例如将const
或volatile
修饰的类型转换为非const
或非volatile
的类型。它是唯一能够执行这种转换的操作符,但是不能用于改变基本类型或执行继承体系间的转换。dynamic_cast
:用于类层次间的下行转换(从基类到派生类),或者类之间的交叉转换(从一个派生类到另一个派生类)。它可以在运行时检查转换的合法性,如果转换失败,会返回空指针或抛出异常。它只能用于含有虚函数的多态类型之间的转换,而且不能用于改变常量性或基本类型。reinterpret_cast
:用于执行低级的、与机器相关的转换,例如将指针转换为整数,或者将函数指针转换为其他类型的函数指针。它是最危险的转型操作符,因为它不保证转换的结果的有效性和可移植性,而且不能用于改变常量性或执行继承体系间的转换。
static_cast
是C++中的一个运算符,用于执行各种不同类型之间的转换,例如基本类型之间的转换,或者类层次间的上行转换(从派生类到基类),或者无关类之间的转换(需要用户自定义转换函数)。
使用语法:
static_cast<type> (expression);
其中,type为目标类型,expression为要转换的表达式。static_cast会根据类型的信息进行编译时的类型检查,以保证转换的合法性和安全性。
下面是一些static_cast的使用场景和示例:
- 基本类型之间的转换:可以将一种基本类型转换为另一种基本类型,例如将double转换为int,或将float转换为double等。这种转换可能会导致精度的损失或溢出,因此需要注意转换的结果是否符合预期。
double d = 3.14;
int i = static_cast<int> (d); // i = 3
float f = 1.23f;
double x = static_cast<double> (f); // x = 1.23
- 指向派生类的指针或引用转换为指向基类的指针或引用:这种转换是安全的,可以实现多态,即通过基类的指针或引用调用派生类的虚函数。
class Base {
public:
virtual void print() { cout << "Base" << endl; }
};
class Derived : public Base {
public:
void print() { cout << "Derived" << endl; }
};
Derived d;
Base* p = static_cast<Base*> (&d); // p指向d的地址
p->print(); // 调用Derived的print函数,输出Derived
- 指向基类的指针或引用转换为指向派生类的指针或引用:这种转换是不安全的,因为static_cast不会进行运行时的类型检查,如果转换的对象不是真正的派生类对象,可能会导致未定义的行为。如果需要进行运行时的类型检查,应该使用dynamic_cast。
Base* p = new Base();
Derived* q = static_cast<Derived*> (p); // q指向p的地址,但p不是Derived的对象
q->print(); // 未定义的行为,可能会崩溃
- 在有关联的类型之间进行转换:例如,转换枚举值为整数,或者调用用户自定义的转换函数。
enum Color { RED, GREEN, BLUE };
int value = static_cast<int> (GREEN); // value = 1
class A {
public:
explicit operator int() { return 42; } // 用户自定义的转换函数
};
A a;
int n = static_cast<int> (a); // n = 42
const_cast
是C++中的一个运算符,用于改变表达式的常量性或易变性,例如将const
修饰的类型转换为非const
的类型。它是唯一能够执行这种转换的C++风格的转型操作符。
使用语法:
const_cast<type> (expression);
其中,type为目标类型,expression为要转换的表达式。const_cast会根据类型的信息进行编译时的类型检查,以保证转换的合法性和安全性。
下面是一些const_cast的使用场景和示例:
- 去除指针或引用的
const
属性:如果有一个指向const
对象的指针或引用,但是需要修改该对象的值,可以使用const_cast去除const
属性,然后通过指针或引用间接修改。这种情况通常发生在函数的参数或返回值中,例如:
// 一个接受const char*参数的函数
void print(const char* str) {
std::cout << str << std::endl;
}
// 一个返回const char*的函数
const char* getHello() {
return "Hello";
}
int main() {
// 一个const char*类型的变量
const char* msg = "World";
// 使用const_cast去除const属性,然后修改值
char* p = const_cast<char*> (msg);
p[0] = 'w';
// 调用print函数,输出world
print(msg);
// 使用const_cast去除const属性,然后修改值
char* q = const_cast<char*> (getHello());
q[0] = 'h';
// 调用print函数,输出hello
print(q);
return 0;
}
- 添加指针或引用的
const
属性:如果有一个指向非const
对象的指针或引用,但是需要将它传递给一个接受const
参数的函数,可以使用const_cast添加const
属性,以避免编译错误。这种情况通常发生在重载函数中,例如:
// 一个类,包含一个非const成员函数和一个const成员函数
class A {
public:
void func() {
std::cout << "non-const func" << std::endl;
}
void func() const {
std::cout << "const func" << std::endl;
}
};
int main() {
// 一个非const对象
A a;
// 调用非const成员函数,输出non-const func
a.func();
// 使用const_cast添加const属性,然后调用const成员函数,输出const func
const_cast<const A&> (a).func();
return 0;
}
需要注意的是,const_cast中:
- 指向函数的指针和指向成员函数的指针不受const_cast约束。
- const_cast可以形成一个指向非
const
类型的引用或指针,它实际上引用了一个const
对象,也可以形成一个指向非volatile
类型的引用或指针,它实际上引用了一个volatile
对象。 - 通过非
const
访问路径修改const
对象会导致未定义的行为。
dynamic_cast是C++中的一个运算符,用于将一个指向基类对象的指针或引用转换为指向派生类对象的指针或引用,同时还会检查转换是否合法。
使用语法:
dynamic_cast<type*> (expression);
其中,type为目标类型,expression为指向基类对象的指针或引用。如果expression指向的是一个派生类对象,则返回指向该派生类对象的指针或引用;否则返回空指针或抛出异常。
dynamic_cast
主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。
- 上行转换(upcasting)是指将指向派生类对象的指针或引用转换为指向基类对象的指针或引用,这种转换是安全的,不需要借助任何特殊的方法,只需用将派生类的指针或引用赋给基类的指针或引用即可,dynamic_cast向上转型其实是多余的。
- 下行转换(downcasting)是指将指向基类对象的指针或引用转换为指向派生类对象的指针或引用,这种转换是不安全的,需要借助dynamic_cast来进行运行时类型检查,以保证转换的有效性。如果转换失败,dynamic_cast会返回空指针或抛出异常,而不会导致未定义的行为。
需要注意的是,dynamic_cast只能用于含有虚函数的类类型之间的转换,因为只有含有虚函数的类类型才能支持运行时类型信息(RTTI)。
下面通过一个简单的例子来说明dynamic_cast的作用:
#include <iostream>
#include <typeinfo>
using namespace std;
// 基类
class Base {
public:
virtual void func() { cout << "Base::func()" << endl; }
};
// 派生类
class Derived : public Base {
public:
void func() { cout << "Derived::func()" << endl; }
void show() { cout << "Derived::show()" << endl; }
};
int main() {
// 上行转换,不需要dynamic_cast
Base* ptr_base = new Derived;
ptr_base->func(); // 多态,调用Derived::func()
// 下行转换,需要dynamic_cast
Derived* ptr_derived = dynamic_cast<Derived*>(ptr_base);
if (ptr_derived != nullptr) { // 转换成功
ptr_derived->func(); // 调用Derived::func()
ptr_derived->show(); // 调用Derived::show()
} else { // 转换失败
cout << "Invalid conversion" << endl;
}
// 交叉转换,需要dynamic_cast
Base* ptr_base2 = new Base;
Derived* ptr_derived2 = dynamic_cast<Derived*>(ptr_base2);
if (ptr_derived2 != nullptr) { // 转换成功
ptr_derived2->func(); // 调用Derived::func()
ptr_derived2->show(); // 调用Derived::show()
} else { // 转换失败
cout << "Invalid conversion" << endl;
}
delete ptr_base;
delete ptr_base2;
return 0;
}
输出结果是:
Base::func()
Derived::func()
Derived::show()
Invalid conversion
可以看到,上行转换不需要dynamic_cast,而下行转换和交叉转换需要dynamic_cast,并且会检查转换的合法性,如果不合法,会返回空指针。
reinterpret_cast
是C++中的一个运算符,用于执行低级的、与机器相关的转换,例如将指针转换为整数,或者将函数指针转换为其他类型的函数指针。它是最危险的转型操作符,因为它不保证转换的结果的有效性和可移植性,而且不能用于改变常量性或执行继承体系间的转换。
使用语法:
reinterpret_cast<type> (expression);
其中,type为目标类型,expression为要转换的表达式。reinterpret_cast会根据类型的信息进行编译时的类型检查,以保证转换的合法性和安全性。
下面是一些reinterpret_cast的使用场景和示例:
- 将指针转换为整数:可以将一个指针转换为一个整数类型,例如int或size_t,这样可以在指针中存储额外的信息,或者将指针作为索引或哈希值使用。
int* p = new int(42); // 一个指向int的指针
size_t n = reinterpret_cast<size_t> (p); // 将指针转换为size_t类型的整数
std::cout << n << std::endl; // 输出整数值,如140732920522000
int* q = reinterpret_cast<int*> (n); // 将整数转换回指针
std::cout << *q << std::endl; // 输出指针指向的值,如42