c++中有很多类型转换的关键字,包括:
- 兼容c的强制类型转换
- static_cast
- dynamic_cast
- reinterpret_cast
- const_cast 本文对这些转换方法进行一些总结
1. c强制类型转换
int num1 = 5;
double num2 = 134878357887823745980.0;
char ch = 'c';
int *pnum1 = &num1;
double *pnum2 = &num2;
// test c-format cast
int test = (int)num2;
int test1 = (int)ch;
long test2 = (long)pnum1;
int test4 = (int)pnum1; // Error: 8bytes --> 4bytes
int test4 = (long)pnum1;
char ch2 = (char)num2;
char ch3 = (char)3876;
可以看得到C风格的转换非常自由,doule<-->int, int<-->long, ptr<-->long, int/long<-->char都不会报错,只有在将ptr转换为int的时候由于占用空间不同出现报错。一般不应该使用c类型的转换方式
2. static_cast
// test static_cast
struct Base {
int a1 = 23;
};
struct Derived: public Base {
int b1 = 33;
};
Base b1;
Derived b2;
int test = static_cast<int>(num2);
int test1 = static_cast<int>(ch);
long test2 = static_cast<long>(pnum1); // Error: value to pointer
int test4 = static_cast<int>(pnum1); // Error: value to pointer
int test5 = static_cast<long>(pnum1); // Error: value to pointer
char ch2 = static_cast<char>(num2);
char ch3 = static_cast<char>(3876);
int test6 = static_cast<int>(b1); // Error: class to int
Base c1 = static_cast<Base>(b2);
int *p1 = static_cast<int*>(p2); // Error: pointer size not fit
Derived c2 = static_cast<Derived>(b1); // Error: up-side is invalid
static_cast在对值类型做转换(int,long,double,char)的时候几乎不做检查, 在对指针做转换的时候会检查指针指向的类型, 对象做转换的时候, 只能子类向父类转换
static_cast使用范围较广,主要在于显式标出了类型转换,表明作者能够接受转换的副作用
3. dynamic_cast
// test dynamic_cast
int test = dynamic_cast<int>(num2);
int test1 = dynamic_cast<int>(ch);
long test2 = dynamic_cast<long>(pnum1);
int test4 = dynamic_cast<int>(pnum1);
int* p1 = dynamic_cast<int*>(pnum1);
Base b1;
Derived b2;
Base c1 = dynamic_cast<Base>(b2);
Base* p2 = dynamic_cast<Base*>(&b2); // Rright
Derived* p3 = dynamic_cast<Derived*>(&b1);
dynamic_cast只能做类指针和引用之间的转换,适用范围较窄。并且也只能由子类向父类转换
4. reinterpret_cast
// test reinterpret_cast
double test0 = reinterpret_cast<double>(num1); // Error: int to double
int test = reinterpret_cast<int>(num2); // Error: double to int
int test1 = reinterpret_cast<int>(ch); // Error: char to int
long test2 = reinterpret_cast<long>(pnum1); // Right: ptr to long -- bytes fit
int test4 = reinterpret_cast<int>(pnum1); // Error: ptr to int -- bytes not fit
int* p1 = reinterpret_cast<int*>(pnum1); // Right: ptr to ptr is always right
Base b1;
Derived b2;
Base c1 = reinterpret_cast<Base>(b2); // Right: to father class
Base* p2 = reinterpret_cast<Base*>(&b2); // Rright
Derived* p3 = reinterpret_cast<Derived*>(&b1); // Error: to son class
reinterpret_cast原理上的解释是,不改变目标的存储bits,只对其进行重新解释。从而可知,将double转化为int/long数值肯定没有意义,从而会失败;指针间进行变换都有意义--默认作者的变换全在掌控范围内;子类对象转换为父类对象也有意义;需要注意的是指针转换为相同bytes的整型默认也有意义
5. const_cast
const_cast用来移除指针或者引用的const性质
{
const int a1 = 33;
int *b1 = const_cast<int*>(&a1);
*b1 = 44;
cout << a1 << " " << *b1 << " " << &a1 << " " << b1 << endl;
}
output:
33 44 0x7ffee1409794 0x7ffee1409794
虽然const_cast能够转化const指针,但是用转换后的指针重新赋值常量,是一个undefined behavior, 上述代码中展示了虽然地址相同,但是a1输出仍保持33不变。原因可以猜测一下(喜欢研究的可以看下反编译代码),编译器在编译阶段认为a1是常量直接用33替换了a1出现的所有位置,所以cout作用域的a1实际上已经替换成了数值33
所以const_cast使用场景基本用于某个函数输入参数用到了常量指针,但是定义的时候忘记了加const关键字,函数体内并不会修改指针指向的内容,此时可以用const_cast转换做一下妥协
6. c风格类型转化与static_cast和reinterpret_cast的关系
c风格的类型转换本质上是先用static_cast进行转换,失败的话尝试用reinterpret_cast