5、static_cast和reinterpret_cast的区别
1、dynamic cast
dynamic_cast操作符将基类类型对象的引用或指针转换为同一继承层次中其它类型的引用或指针。与dynamic_cast一起使用的指针必须是有效的,它必须为0或指向一个对象。与另外三种强制类型转换不同,dynamic_cast涉及运行时类型检查。如果绑定到引用或指针的对象不是目标类型的对象,则dynamic_cast失效。如果转换到指针类型的dynamic_cast失败,则dynamic_cast的结果是0值;如果转换到引用类型的dynamic_cast失败,则抛出一个bad_cast类型的异常。
- 指针转换语法:dynamic_cast<*Derived> (*Base)
- 引用转换语法:dynamic_cast<Type&> (val);
2、const_cast
const_cast的作用如下:
- 将转换掉表达式的const性质;
- 只有使用const_cast才能将const性质性质转化掉,试图使用其他三种形式的强制转换都会导致编译时的错误;
- 除了添加const或删除const特性,使用const_cast符来执行其他任何类型的转换都会引起编译错误。
示例:
int main()
{
const int constant = 26;
const int* const_p = &constant;
int* modifier = const_cast<int*>(const_p);
*modifier = 3;
cout<< "constant: "<<constant<<endl;
cout<<"*modifier: "<<*modifier<<endl;
system("pause");
}
输出:
26
3
对声明为const的变量来说,常量就是常量,任你各种转化,常量的值就是不会变。这是C++的一个承诺。那既然const变量的值是肯定不会发生变化的,还需要这个const_cast类型转化有何用?这就引出了const_cast的最常用用法:如果有一个函数,它的形参是non-const类型变量,而且函数不会对实参的值进行改动,这时我们可以使用类型为const的变量来调用函数,此时const_cast就派上用场了。
void InputInt(int * num)
{
cout<<*num<<endl;
}
int main()
{
const int constant = 21;
//InputInt(constant); //error C2664: “InputInt”: 不能将参数 1 从“const int”转换为“int *”
InputInt(const_cast<int*>(&constant));
system("pause");
}
总结:const_cast绝对不是为了改变const变量的值而设计的,在函数参数的传递上const_cast的作用才显现出来。
3、static_cast
编译器隐式执行的任何类型转换都可以由static_cast显式完成。当需要将一个较大的算术类型赋值给较小类型时,使用强制类型转换非常有用。此时强制类型转换告诉程序的读者和编译器:我们知道并且不关心潜在的精度损失。对于从一个较大的算术类型到一个较小类型的赋值,编译器通常会产生警告。当我们显式提供强制类型转换时,警告信息将会被关闭。比如:
double d = 97.0;
char ch = static_cast<char> d;
4、reinterpret_cast
reinterpret_cast通常为操作数的位模式提供较低层次的重新解释,它从二进制重新映射解释,不会进行类型安全检查,甚至可以在两个无关的类型之间进行转换。比如:
int main() {
int a = 10;
int *p = &a;
int b = reinterpret_cast<int>(p);
cout << b << endl;
return 0;
}
使用reinterpret_cast甚至可以从一个指针类型转为一个int类型,不进行类型安全检查,这个转换是非常安全的。
5、static_cast和reinterpret_cast的区别
- reinterpret_cast可以转换任意一个32bit整数,包括所有的指针和整数。可以把任何整数转成指针,也可以把任何指针转成整数,以及把指针转化为任意类型的指针,威力最为强大!但不能将非32bit的实例转成指针。总之,只要是32bit的东东,怎么转都行。
- static_cast和dynamic_cast可以执行指针到指针的转换,或实例本身到实例本身的转换,但不能在实例和指针之间转换。static_cast只能提供编译时的类型安全,而dynamic_cast可以提供运行时类型安全。
实例1;
int main() {
int a = 10;
int *p = &a;
int b = reinterpret_cast<int>(p); //编译通过
float *q = reinterpret_cast<float*>(p); //编译通过
//int b = static_cast<int>(p); 编译不通过:error C2440: “static_cast”: 无法从“int *”转换为“int”
//float *q = static_cast<float*>(p); 编译不通过:error C2440: “static_cast”: 无法从“int *”转换为“float *”
cout << q << endl;
cout << b << endl;
return 0;
}
实例2:
class A
{
public:
A(int m = 1) :m(m) {}
int m;
};
class B
{
public:
B(int m = 2) :m(m) {}
int m;
};
class C :public A, public B
{
public:
C() {}
};
int main() {
C c;
cout << &c << endl;
cout << sizeof(c) << endl<<endl;
B *b1 = reinterpret_cast<B*>(&c);
cout << b1 << endl;
cout << sizeof(*b1) << endl;
cout <<"b1:m = "<< b1->m << endl<<endl;
B *b2 = static_cast<B*>(&c);
cout << b2 << endl;
cout << sizeof(*b2)<<endl;
cout <<"b2:m = "<< b2->m<<endl;
return 0;
}
输出:
00F3FC6C
8
00F3FC6C
4
b1:m = 1
00F3FC70
4
b2:m = 2
可以看出,使用reinterpret_cast从派生类到基类的转换时,指针的地址并没改变。而使用static_cast从派生类到基类的转换时,指针的地址发生了改变,指针此时变成一个指向基类的指针,指针的地址仍然位于派生类的地址空间中。
6、关于算术提升的一些坑
(1)当从一个精度较高的类型(比如int、unsigned int)赋值给一个精度较低的类型(如short、unsigned short)时,精度较低的类型直接从高精度类型的低字节截取即可。
(2)但是反过来,当从一个精度较低的类型(如short、unsigned short)赋值给一个精度较高的类型(比如int、unsigned int short)时,精度较高的类型的高字节部分用什么填充呢,这里要分为两种情况:
- 如果低精度类型的第一个bit位为1,那么高精度类型的所有高字节部分用1填充;
- 如果低精度类型的第一个bit位为0,那么高精度类型的所有高字节部分用0填充。
int main() {
char a1 = 54;
bitset<8> bit_a1(a1);
cout << "bit_a1:"<<bit_a1<< endl;
unsigned short b1 = a1;
cout << "b1:"<<b1 << " bit_b1:";
bitset<16> bit_b1(b1);
cout << bit_b1 << endl<<endl;
char a2 = 130;
bitset<8> bit_a2(a2);
cout << "bit_a2:"<< bit_a2 << endl;
unsigned short b2 = a2;
cout << "b2:"<<b2 << " bit_b2:";
bitset<16> bit_b2(b2);
cout << bit_b2 << endl;
return 0;
}
输出:
bit_a1:00110110
b1:54 bit_b1:0000000000110110
bit_a2:10000010
b2:65410 bit_b2:1111111110000010
int main() {
char a = 127;
char b = 128;
unsigned short c = 200;
cout << a + c << endl; //类型不同的相加得到的结果为int
cout << typeid(a + c).name() << endl;
cout << b + c << endl;
cout << typeid(a + b).name() << endl; //类型相同的相加得到的结果也为int
return 0;
}
输出:
327
int
72
int