【C++】类型转换

您所在的位置:网站首页 gps能精确到多少 【C++】类型转换

【C++】类型转换

2023-05-27 01:23| 来源: 网络整理| 查看: 265

文章目录 1. C语言中的类型转换2. 为什么C++需要四种类型转换3. C++强制类型转换static_castreinterpret_castconst_castdynamic_cast 4.explicit5.RTTI6.考点

1. C语言中的类型转换

在C语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与接收返回值类型不一致时,就需要发生类型转化,C语言中总共有两种形式的类型转换:隐式类型转换和显式类型转换

隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译失败, 相近类之间才可以,比如int型转化为double型 (提升和截断本质就是隐式类型转化)显式类型转化:需要用户自己处理, 不相近类型(意义差别很大的类型) ,比如强制类型转换:int型转化为int*型

需要注意的是,只有相近类型之间才能发生隐式类型转换,比如int和double表示的都是数值,只不过它们表示的范围和精度不同.而指针类型表示的是地址编号,因此整型和指针类型之间不会进行隐式类型转换,如果需要转换则只能进行显式类型转换.比如:

void Test () { int i = 1; // 隐式类型转换 double d = i; printf("%d, %.2f\n" , i, d); int* p = &i; // 显示的强制类型转换 int address = (int) p; printf("%x, %d\n" , p, address); }

缺陷: 转换的可视性比较差,所有的转换形式都是以一种相同形式书写,难以跟踪错误的转换

例如:下述这个存在错误的代码:

string& insert(size_t pos, char ch) { assert(pos _str[end+1] = _str[end]; --end; } _str[pos] = ch;//把字符插入到pos位置 _size++;//数据个数+1 return *this; }

这里的end和pos进行比较,会发生类型提升, 其实本质就是隐式类型转化

当end减到-1的时候,本来应该要结束的, 但是size_t end = -1,代表的值是42亿多, 导致循环无法结束,就是因为end从int类型提升为size_t类型!

解决方法: end改为size_t类型也是不行的, 必须防止end变为-1的情况 可以用指针拷贝

2. 为什么C++需要四种类型转换

C风格的转换格式很简单,但是有不少缺点的

隐式类型转化有些情况下可能会出问题:比如数据精度丢失显式类型转换将所有情况混合在一起,代码不够清晰

因此C++提出了自己的类型转化风格,注意因为C++要兼容C语言,所以C++中还可以使用C语言的转化风格

3. C++强制类型转换

标准C++为了加强类型转换的可视性,引入了四种命名的强制类型转换操作符:

static_cast、reinterpret_cast、const_cast、dynamic_cast

static_cast

**static_cast用于非多态类型的转换(静态转换) ** 相近类型的转化

编译器隐式执行的任何类型转换都可用static_cast,但它不能用于两个不相关的类型进行转换

int main() { double d = 12.34; int a = static_cast(d); cout cout //const修饰的是常变量 const int a = 10; int* p = const_cast(&a); //去掉了const属性 *p = 100; cout public: virtual void f() {} }; class B : public A {}; void func(A* pa) { B* pb1 = (B*)pa; //不安全 B* pb2 = dynamic_cast(pa); //安全 cout public: virtual void f() {} int _a; }; class B : public A { public: int _b = 0; }; //如果pa是指向父类对象,那么不做任何处理 //如果pa是指向子类对象,那么请转回子类,并访问子类对象中_b成员 //父类指针可以接收子类指针 和 父类指针 void func(A* pa) { // dynamic_cast(pa)--如果pa指向的父类对象,那么则转换不成功,返回nullptr // 如果pa指向的子类对象,那么则转换成功,返回指向对象指针 B* pb1 = dynamic_cast(pa); if (pb1 == nullptr) { cout A aa; B bb; func(&aa); func(&bb); //父类对象不能赋值给子类对象!!! //bb = reinterpret_cast(aa); // reinterpret_cast也不允许 }

image-20220801121055205

原理:

image-20220801121641454

注意:强制类型转换关闭或挂起了正常的类型检查,每次使用强制类型转换前,程序员应该仔细考虑是否还有其他不同的方法达到同一目的,如果非强制类型转换不可,则应限制强制转换值的作用域,以减少发生错误的机会

强烈建议:避免使用强制类型转换

4.explicit

explicit用来修饰构造函数,从而禁止单参数构造函数进行的隐式转换.比如:

class A { public : explicit A (int a) //单参构造函数 { cout A a1 (1); // 隐式转换->1) 先调用单参构造函数生成一个临时对象 A tmp(1) 2) 然后拷贝构造a2 A a2(tmp); A a2 = 1;//由于explicit修饰了单参构造函数,所以不允许隐式类型转化! 报错 return 0; }

A a2 = 1 等价于: A tmp(1); //先构造 A a2(tmp); //再拷贝构造

所以在早期的编译器中,当编译器遇到A a2 = 1这句代码时,会先构造一个临时对象,再用这个临时对象拷贝构造a2.但是现在的编译器已经做了优化,当遇到A a2 = 1这句代码时,会直接按照A a2(1)的方式进行处理,这叫做隐式类型转换.

但对于单参数的自定义类型来说,A a2 = 1这种代码的可读性不是很好,因此可以用explicit修饰单参数的构造函数,从而禁止单参数构造函数的隐式转换.

5.RTTI

RTTI:Run-time Type identification的简称,即:运行时类型识别

C++通过以下方式来支持RTTI:

typeid操作符 typeid用于返回指针或引用所指对象的实际类型 class A { virtual void f() {} public: }; class B : public A { public: int _b = 0; }; int main() { B b; A& a = b; cout


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3