【More Effective C++ 条款2】最好使用C++转型操作符
C的转型方式存在以下两个缺点:
1)几乎允许你将任何类型转化为任何类型,不能精确的指明转型意图,这样很不安全
如将一个pointer-to-base-class-object转型为一个pointer-to-derived-class-object(改变一个对象的类型)和将一个pointer-to-const-object转型为一个pointer-to-non-const-object(改变对象的常量性),在旧式C语法中并不区分。
2)其语法结构难以辨识,容易被混淆
旧式C转型方式的语法为(type)expression,由一对小括号加上一个对象名称组成,而这种语法结构在C++的任何地方都有可能使用,这就无法很直观地判断出是否是转型操作。
为了解决C旧式转型的缺点,C++引用了4个新的转型操作符
1)static_cast
static_cast基本上拥有和C旧式转型相同的威力与意义
#include<bits/stdc++.h>
using namespace std;
int main()
{
//计算两个int型数相除,结果为double型
int first_num=1;
int second_num=2;
double ans1 = (double)first_num/second_num;//旧式C语法
double ans2 = static_cast<double>(first_num)/second_num;//新式C++转型符
cout<<ans1<<endl;//0.5
cout<<ans2<<endl;//0.5
}
但是static_cast不能移除表达式的常量性,因为有一个专门的转型操作符const_cast来处理这种情况
2)const_cast
const_cast用来移除表达式中的常量性或者变易性,也仅仅只有这个功能
只能是const_cast<对象的引用或对象的指针>的形式,不能是const_cast<对象>的形式
#include<bits/stdc++.h>
using namespace std;
int main()
{
int num=10;
const int *cpNum=#
//int *p1=cpNum; //error:cannot convert from 'const int *' to 'int *'
int *p2=(int*)cpNum; //旧式C
int *p3=const_cast<int*>(cpNum); //新式C++const_cast移除常量性 cout<<*p2<<endl;//10
cout<<*p3<<endl;//10
}
const_cast最常见的用途就是将某个对象的常量性去除掉
3)dynamic_cast
用来执行继承体系中安全的向下转型或跨系转型动作,dynamic_cast支持RTTI运行时类型检查
比如将指向基类对象的指针或引用转型为子类对象的指针或引用,并且可以得知转型是否成功,如果转型失败会以一个空指针(转型对象为指针)或异常(转型对象为引用)
需要注意的是,dynamic_cast无法应用在缺乏虚函数的类上,理由如下:
dynamic_cast的转换是在运行时进行转换,运行时转换就需要知道类对象的信息(继承关系等),而要获得这些信息,就需要通过虚函数表,在C++对象模型中对象实例最前面的就是虚函数指针,通过虚函数表指针可以获取到该类对象的所有虚函数,包括父类的,因为派生类会继承基类的虚函数表,所以通过这个虚函数表,我们就可以知道该类对象的父类,在转换的时候就可以判断对象有无继承关系
另外,dynamic_cast支持交叉转换,基类A有两个直接派生类B和C,那么将B类对象指针/引用转换为C类对象指针/引用的转换称之为交叉转换
class Base
{
virtual void fun()
{
cout << "Base" << endl;
}
}; class Derived :Base
{
virtual void fun()
{
cout << "Derived" << endl;
}
}; Base* bbb = new Base();
Derived* aaa = dynamic_cast<Derived*> (bbb);
Derived& ccc = dynamic_cast<Derived&> (*bbb);
如果你需要转换一个不涉及继承体制的请使用:static_cast,dynamic_cast仅仅适用于那种”所指对象至少有一个虚函数“的指针身上。
4)reinterpret_cast
最常用的用途是转换“函数指针”,但是函数指针的转型动作,并不具备移植性,某些情况下函数指针转型会导致不正确的结果,所以我们应该尽量避免将函数指针转型
typedef void (*FuncPtr)() //FuncPtr是个指针,指向某个函数,后者无需任何自变量,返回值为void
FuncPtr funcPtrArray[10] //funcPtrArray是个数组,内含10个FuncPtr
假设现在有某种原有,需要将一个返回值为int类型的函数放入funcPtrArray
int dosomething()
将int类型函数指针放入int类型函数指针数组,如果没有转型的话,是不可能做到这一点的
funcPtrArray[0]=&dosomething //错误,类型不符合
使用reinterpret_cast,可以强迫编译器了解你的意图
funcPtrArray[0]=reinterpret_cast<FuncPtr>(&dosomething) //正确,将int类型函数指针转换为void类型
【More Effective C++ 条款2】最好使用C++转型操作符的更多相关文章
- [More Effective C++]条款22有关返回值优化的验证结果
(这里的验证结果是针对返回值优化的,其实和条款22本身所说的,考虑以操作符复合形式(op=)取代其独身形式(op),关系不大.书生注) 在[More Effective C++]条款22的最后,在返回 ...
- More Effective C++ 条款0,1
More Effective C++ 条款0,1 条款0 关于编译器 不同的编译器支持C++的特性能力不同.有些编译器不支持bool类型,此时可用 enum bool{false, true};枚举类 ...
- Effective C++ 条款27
尽量少做转型动作 尽量少做转型动作有什么目的?非常明显无非就是提高程序的稳定性.提高程序的运行效率. 那么.有哪些转型方式?每种方式都有什么弱点? 这是我们本节学习的重点. C++有四种转型: con ...
- Effective C++ 条款08:别让异常逃离析构函数
1.别让异常逃离析构函数的原因 <Effective C++>第三版中条款08建议不要在析构函数中抛出异常,原因是C++异常机制不能同时处理两个或两个以上的异常.多个异常同时存在的情况下, ...
- Effective C++ -----条款28:避免返回handles指向对象内部成分
避免返回handles(包括reference.指针.迭代器)指向对象内部.遵守这个条款可增加封装性,帮助const成员函数的行为像个const,并将发生“虚吊号码牌”(dangling handle ...
- Effective C++ -----条款21:必须返回对象时,别妄想返回其reference
绝不要返回pointer或reference指向一个local stack对象,或返回reference指向一个heap-allocated对象,或返回pointer或reference指向一个loc ...
- Effective C++ -----条款19:设计class犹如设计type
Class的设计就是type的设计.在定义一个新type之前,请确定你已经考虑过本条款覆盖的所有讨论主题. 新type的对象应该如何被创建和销毁? 对象的初始化和对象的赋值该有什么样的区别? 新typ ...
- Effective C++ -----条款18:让接口容易被正确使用,不易被误用
好的接口很容易被正确使用,不容易被误用.你应该在你IDE所有接口中努力达成这些性质. “促进正确使用”的办法包括接口的一致性,以及与内置类型的行为兼容. “阻止误用"的办法包括建立新类型.限 ...
- Effective C++:条款27——条款
条款27:尽量少做转型动作 单一对象可能拥有一个以上的地址!
- Effective C++ 条款45
本节条款的题目是运用成员模板接受全部兼容类型 作者阐述自己的观点是通过智能指针的样例. 在学习本节条款之前我们要先明确关于隐式转化的问题 例如以下代码: #include<iostream> ...
随机推荐
- spring cloud 框架源码 activiti工作流 vue.js html 跨域 前后分离 springboot
1.代码生成器: [正反双向](单表.主表.明细表.树形表,快速开发利器)freemaker模版技术 ,0个代码不用写,生成完整的一个模块,带页面.建表sql脚本.处理类.service等完整模块2. ...
- python 树与二叉树的实现
1.树的基本概念 1.树的定义 树的定义是递归的,树是一种递归的数据结构. 1)树的根结点没有前驱结点,除根结点之外所有结点有且只有一个前驱结点 2)树中所有结点可以有零个或多个后继结点 2.树的术语 ...
- WIP表解析
1,WIP的作用 负责纪录生产相关信息,生产什莫--工单的制定,下达,生产步鄹--工序及其移动,投入什莫--组件需求和投料,资源投入入和费用吸收,负责纪录生产成本的归集和差异分析,投入多少组件,资 ...
- Windows下面startup.bat启动Tomcat偶发死锁问题
Windows下面startup.bat启动Tomcat时,因为日志都打印到了cmd里面,存在偶发卡死Tomcat的问题,该问题确认是Windows系统的问题,而且一直没有解决.解决的办法是把日志重定 ...
- Centos7 安装chrony服务
从Centos7 开始,新增了一条时间查询命令:timedatectl [root@c2 ~]# timedatectl Local -- :: CST Universal -- :: UTC RTC ...
- Rust中的Vector类型
常用类型操作, 如python中的list,turple,dictory等, 更方常编程常用数据的处理. fn main() { let v = vec![, , , , ]; let third: ...
- 3-剑指Offer: 连续子数组的最大和
题目描述 HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学.今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决.但是,如果向量 ...
- xenserver 添加和卸载硬盘
最近在浪潮服务器上安了xenserver系统,创建虚拟机,没注意磁盘超负载就重启了服务导致各种坑,一言难尽,忧伤逆流成河啊,所以准备将各种操作整理总结记录下,持续更新ing~~ ...
- v8/src/compilation-statistics.cc pdfium编译
v8/src/compilation-statistics.cc:18:3: 警告:‘auto’ changes meaning in C++11; please remove it [-Wc++0x ...
- Python Treelib 多叉树 数据结构 中文使用帮助文档
树,对于计算机编程语言来说是一个重要的数据结构.它具有广泛的应用,比如文件系统的分层数据结构和机器学习中的一些算法.这里创建了treelib来提供Python中树数据结构的高效实现. 官方文档:htt ...