目录
c语言的类型转换可以分为隐式类型转换和强制类型转换。
- #include
-
- 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的时候不会产生临时对象。只需要将这种方式作为编译器支持的原生方式转换就好。
- #include
-
- 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突然搞那么大,就必然跑不出去了奥。
a.static_cast
和隐式类型转换一样。
问题:不支持类型差距太大的转换
b.reinterpret_cast
问题: 不支持去除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(pa);
- //转换为B*(子类)
-
- if (pb)
- {
- cout << "转换成功" << endl;
- }
- else
- {
- cout << "转换失败" << endl;
- }
- }
- int main()
- {
- A a; B b;
- fun(&a);
- fun(&b);
- }
若是传入A(父类),是一种不安全的转换(可能存在越界问题)。
看图:
建议使用c++提供的指定类型转换关键字,这种方式更加安全。可以避免隐式类型转换的坑,并且还提供了dynamic_cast和const_cast来处理特殊问题。