目录
1.隐式类型转换和强制类型转换
2.隐式类型转换带来的危险
3.c++提供的标准类型转换关键字
4.总结
1.隐式类型转换和强制类型转换
c语言的类型转换可以分为隐式类型转换和强制类型转换。
#include<iostream>
using namespace std;
int main()
{
double a = 3.14;
int b = a;
cout << b << endl;
int* p = &b;
int pp = (int)p;
cout << pp << endl;
return 0;
}
这里的转换的前提都是这两个类型意义相近。
ps:要区别继承中的切割和隐式类型转换。
class A
{
public:
A()
:_a(0)
{}
private:
int _a;
};
class B :public A //继承A
{
public:
B()
:_b(0)
,A()
{}
private:
int _b;
};
int main()
{
B b;
A a = b;//一种原生支持的切割
return 0;
}
我们要知道隐式类型转换的共性是要生成一个临时对象,明显将b赋值给a的时候不会产生临时对象。只需要将这种方式作为编译器支持的原生方式转换就好。
2.隐式类型转换带来的危险
#include<iostream>
using namespace std;
void Move(size_t pos)
{
int end = 4;
while (end >= pos) //发生了隐式类型转换,将int的end转换成了size_t无符号数
{
//arr[end + 1] = arr[end]; 向后挪
end--;
}
}
int main()
{
Move(0);
return 0;
}
这段程序死循环了。
原因是:当end减到-1才应该退出循环,但是因为end和pos在表达式的两边。且两个数意义相近
,因此end变成了无符号数,-1就变成了整形的最大值(要了解负数补码和无符号数的定义)。
end突然搞那么大,就必然跑不出去了奥。
3.c++提供的标准类型转换关键字
a.static_cast<T>
和隐式类型转换一样。
问题:不支持类型差距太大的转换
b.reinterpret_cast<T>
问题: 不支持去除const属性
c.const_cast
常用来给const变量赋值(去除const属性):
const int a = 3;
int* pp = const_cast<int*>(&a);
*pp = 4;
cout << a << endl;
这里有一个奇怪的现象:
显示的结果为a的值依然是3,再通过调试看看内存中a的值:
太神奇了,内存中显示a是4诶。
实际上,这和ide的处理有关,在vs环境下const变量并不是存于常量区中。而是存在一个特殊寄存器中,本质也在栈中。调用时,内存中的const变量就算在内存中发生了变化,但由于已经被寄存器将之前的值读出了,所以我们看见的结果没有发生变化。
d.dynamic_cast
dynamic_cast用于父子类的向下赋值,向上赋值原生支持(切割)。
class A
{
public:
virtual void f() {}
};
class B : public A //继承A
{};
void fun(A* pa)
{
// dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回。
B* pb = dynamic_cast<B*>(pa);
//转换为B*(子类)
if (pb)
{
cout << "转换成功" << endl;
}
else
{
cout << "转换失败" << endl;
}
}
int main()
{
A a; B b;
fun(&a);
fun(&b);
}
若是传入A(父类),是一种不安全的转换(可能存在越界问题)。
看图:
4.总结
建议使用c++提供的指定类型转换关键字,这种方式更加安全。可以避免隐式类型转换的坑,并且还提供了dynamic_cast和const_cast来处理特殊问题。