C++的转换手段并与explicit关键词配合使用
前言
C中我们会进行各种类型的强制转化,而在C中我们经常可以看到这种转换
memset(OTA_FLAG_ADDRESS,(uint8_t*)&OTA_Flag,sizeof(OTA_Flag));
而C++的类型转化和C差别很多,那么C++里面的类型转化是怎么用的呢。C++除了隐式转换和显示转化,显示转化是我们熟知,有四个显示转化函数:static_cast、dynamic_cast、const_cast、reinterpret_cast,主要运用于继承关系类间的强制转化。
下面我就给大家说道说道。
作者:良知犹存
转载授权以及围观:欢迎添加微信公众号:羽林君
**隐式转化
**
c++语言不会直接将两个不同类型的值相加,二十先根据类型转化规则设法将运算对象的类型统一后再求值。例如 int value = 3.14 +3;这个程序是可以编译通过的,只不过编译器可能会警告改运算损失了精度。这样的类型转化是自动运行,无需程序员介入,因此,它们被称为隐式转换
**何时会发生隐式转化:
**在下面的情况中,编译器会自动的转化运算对象的类型:
- 在大多数表达式中,需要将比int类型小的整型值首先提升到较大的整数类型会进行隐式转化
- 在条件中,非布尔值转换成布尔类型
- 初始化过程中,初始值转化成变量的类型;在赋值语句中,右侧运算对象转化成左侧运算对象的类型
- 函数调用时候也会发生类型转化(实参类型转化)
显示转化
C风格的强制转换(Type Cast)容易理解,不管什么类型的转换都可以使用使用下面的方式
Type b = (Type)a;
当然,C++也是支持C风格的强制转换,但是C风格的强制转换可能带来一些隐患,让一些问题难以察觉.所以C++提供了一组可以用在不同场合的强制转换的函数.
C++提供了四种强制类型转化的函数,分别是:
****static_cast,命名上理解是静态类型转换。大部分C实现的转化,用这个函数就可以了。
const_cast,字面上理解就是去const属性。
dynamic_cast,命名上理解是动态类型转换。如子类和父类之间的多态类型转换。
reinterpret_cast,仅仅重新解释类型,但没有进行二进制的转换。
static_cast:
任何具有明确定义的类型转化,只要不包含底层const,都可以使用static_cast,举一个例子。
double slop = static_cast<double>(j) / i;//进行强制转化成double
int*pn =&n;
double*dp = static_cast<double*>(&pn) //无关类型指针转换,编译错误
void*p = &n;
double*d = static_cast<double*>(&p) //将void*转化为初始的指针类型
static_cast强制转换只会在编译时检查,但没有运行时类型检查来保证转换的安全性。同时,static_cast也不能去掉expression的const、volitale、或者__unaligned属性。
const_cast:
const_cast<>可以实现将const 指针类型转普通指针,const_cast操作不能在不同的种类间转换。相反,它仅仅把一个它作用的表达式转换成常量。它可以使一个本来不是const类型的数据转换成const类型的,或者把const属性去掉。如果一个对象本身不是一个常量,使用强制类型转化获得写权限是合法的行为。然而如果对象是一个常量,再使用const_cast执行写操作就会产生未定义的后果。
只有const_cast能改变表达式的常量属性,使用其他形式的命名强制类型转化改变表达式的常量属性都将引发编译器错误。同样的,也不能用const_cast改变表达式的类型:
const char *cp;
char *q = static_cast<char *>(cp);//错误:static_cast不能转换掉const性质
static_cast<string>(cp);//正确:字符串字面值转换成string类型
const_cast<string>(cp);//错误:const_cast 只改变常量属性
const_cast<char*>(cp);//正确
const int p = 0;
int &rb = const_cast<int&>(p);//正确
rb =10;
dynamic_cast:
1.其他三种都是编译时完成的,dynamic_cast是运行时处理的,运行时要进行类型检查。
2.不能用于内置的基本数据类型的强制转换。
3.dynamic_cast转换如果成功的话返回的是指向类的指针或引用,转换失败的话则会返回NULL。
4.使用dynamic_cast进行转换的,基类中一定要有虚函数,否则编译不通过。可以从父类转基类,但是可能为空
5.在类的转换时,在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的。在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。向上转换即为指向子类对象的向下转换,即将父类指针转化子类指针。向下转换的成功与否还与将要转换的类型有关,即要转换的指针指向的对象的实际类型与转换以后的对象类型一定要相同,否则转换失败。
class BaseClass {
public:
int Num;
virtualvoid foo(){}; //基类必须有虚函数。保持多台特性才能使用dynamic_cast
};
DerivedClass: public BaseClass {
public:
char*m_szName[100];
void bar(){};
};
int main(int argc,char** argv)
{
BaseClass* pb =new DerivedClass();
DerivedClass *pd1 = static_cast<DerivedClass *>(pb); //子类->父类,静态类型转换,正确但不推荐
DerivedClass *pd2 = dynamic_cast<DerivedClass *>(pb); //子类->父类,动态类型转换,正确
BaseClass* pb2 =new BaseClass();
DerivedClass *pd21 = static_cast<DerivedClass *>(pb2); //父类->子类,静态类型转换,危险!访问子类m_szName成员越界
DerivedClass *pd22 = dynamic_cast<DerivedClass *>(pb2); //父类->子类,动态类型转换,安全的。结果是NULL
reinterpret_cast:
实现指针转整形,整形转指针.reinterpret_cast是强制类型转换符用来处理无关类型转换的,通常为操作数的位模式提供较低层次的重新解释!但是它仅仅是重新解释了给出的对象的比特模型,并没有进行二进制的转换!
它是用在任意的指针之间的转换,引用之间的转换,指针和足够大的int型之间的转换,整数到指针的转换。最普通的用途就是在函数指针类型之间进行转换。
请看一个简单代码
int doSomething(){return 0;};
typedef void(*FuncPtr)(); //FuncPtr is 一个指向函数的指针,该函数没有参数,返回值类型为 void
FuncPtr funcPtrArray[10]; //10个FuncPtrs指针的数组 让我们假设你希望(因为某些莫名其妙的原因)把一个指向下面函数的指针存入funcPtrArray数组:
funcPtrArray[0] =&doSomething;// 编译错误!类型不匹配,reinterpret_cast可以让编译器以你的方法去看待它们:funcPtrArray
funcPtrArray[0] = reinterpret_cast<FuncPtr>(&doSomething); //不同函数指针类型之间进行转换
explicit关键字(显示的类型转化运算符)
C++提供了关键字explicit,可以阻止不应该允许的经过转换构造函数进行的隐式转换的发生。即声明为explicit的构造函数不能在隐式转换中使用。
explicit关键字只能用于类内部的构造函数声明上,而不能用在类外部的函数定义上。现在Things类像这样:
class Things
{
public:
Things(const std::string&name ="");
explicit operator int() const{return val;}
//编译器不会自动执行这一类型的
};
下面再看个好一点的例子进行对比一下:
// 类的通过构造函数的隐式转换:#include <iostream>
using namespace std;
class A {};
class B {
public:
// conversion from A (constructor):
B (const A& x) {}
// conversion from A (assignment):
B& operator= (const A& x) {return *this;}
// conversion to A (type-cast operator)
operator A() {return A();}
};
int main ()
{
A foo;
B bar = foo; // 调用构造函数实现隐式类型转换
bar = foo; // calls assignment
foo = bar; // calls type-cast operator,相当于 foo = A(bar);
return 0;
}
再看使用explicit的一个例子:
#include <iostream>
using namespace std;
class A {};
class B {
public:
explicit B (const A& x) {}
B& operator= (const A& x) {return *this;}
operator A() {return A();}
};
void fn (B x) {} // 当我们希望x只能是B类型时,我们就需要禁止隐式类型转换
int main ()
{
A foo;
B bar (foo); // 必须显式类型转换,不再允许B bar = foo;
bar = foo;
foo = bar;
// fn (foo); // 不允许隐式类型转换
fn (bar);
return 0;
}
这就是我分享的c++的转化类型方法,其中参考了好多人的文字,此外如果大家有什么更好的思路,也欢迎分享交流哈。
*—*END*—*
推荐阅读
【1】c++nullptr(空指针常量)、constexpr(常量表达式)
【2】嵌入式底层开发的软件框架简述
【3】CPU中的程序是怎么运行起来的 必读
【4】C++的匿名函数(lambda表达式)
【5】阶段性文章总结分析
本公众号全部原创干货已整理成一个目录,回复[ 资源 ]即可获得.
参考链接:
C++ primer 第五版
https://blog.csdn.net/shuzfan/article/details/77338366
https://www.cnblogs.com/goodhacker/archive/2011/07/20/2111996.html
更多分享,扫码关注我
C++的转换手段并与explicit关键词配合使用的更多相关文章
- C#自定义转换(implicit 或 explicit)
C#的类型转换分为显式转换和隐式转换,显式转换需要自己声明转换类型,而隐式转换由编译器自动完成,无需我们声明,如: //long需要显式转换成int long l = 1L; int i = (int ...
- C++中的explicit关键字 - 抑制隐式转换(转)
在C++程序中很少有人去使用 explicit 关键字,不可否认,在平时的实践中确实很少能用的上.再说C++的功能强大,往往一个问题可以利用好几种C++特性去解决.但稍微留心一下就会发现现有的MFC库 ...
- C#中如何利用操作符重载和转换操作符
操作符重载 有的编程语言允许一个类型定义操作符应该如何操作类型的实例,比如string类型和int类型都重载了(==)和(+)等操作符,当编译器发现两个int类型的实例使用+操作符的时候,编译器会生成 ...
- explicit constructor(显示构造函数)
按照默认规定,只有一个参数的构造函数也定义了一个隐式转换,将该构造函数对应的数据类型的数据转换为该类对象,如下所示: class String { String(const char* p) //用C ...
- c++构造函数隐式转换--转换构造函数
其实我们已经在C/C++中见到过多次标准类型数据间的转换方式了,这种形式用于在程序中将一种指定的数据转换成另一指定的类型,也即是强制转换,比如:int a = int(1.23),其作用是将1.23转 ...
- 编程练习------C/C++分别实现字符串与整数的转换
C/C++分别实现字符串与整数的转换 前提:不使用 itoa 和 atoi. 方法一.C和C++通用的一种转换手段是: 1.整数转化为字符串:采用加'0',再逆序的办法,整数加'0'就会隐性转化成ch ...
- C#图解教程 第十六章 转换
转换 什么是转换隐式转换显式转换和强制转换 强制转换 转换的类型数字的转换 隐式数字转换溢出检测上下文 1.checked和unchecked运算符2.checked语句和unchecked语句 显式 ...
- C++关键字之explicit(显式)
C++ Code 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849 ...
- 【c++】explicit 隐式类类型转换
上代码 #include <iostream> #include <sstream> using namespace std; class A { public: A(cons ...
随机推荐
- VUE项目性能优化实践——通过懒加载提升页面响应速度
本文由葡萄城技术团队原创并首发 转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 最近我司因业务需求,需要在一个内部数据分析平台集成在线Excel功能,既然我 ...
- VMware虚拟机安装黑群晖DSM6.2 (转)
安装DSM6.2.和安装5.1的过程大致相同,只是在虚拟机的配置时有所不同. 需要用到的工具 Roadkil's Disk Image – 写镜像工具:http://www.roadkil.net/p ...
- 【分享】wdcp服务器管理系统常用维护工具
wdcp (WDlinux Control Panel) 是一套用PHP开发的Linux服务器管理系统,类似国外流行的cpanel,旨在易于使用和管理Linux服务器,可以在线通过网页管理服务器和虚拟 ...
- MySQL更新勿用and
项目实战 一次错误的更新 更新前的数据 执行更新语句 然后我们查看下更新后的数据,发现居然数据为空? 使用主键id的方式查询这条数据,发现需要更新的手机号码居然变为了0 当我们把更新语句中的and ...
- Python列表推导式玩法
前言 列表做为python的基础,是必须学习的语法之一.一些基础的之前已经是反复温习和使用了,今天我们来学习它的进阶版-->列表推导式. 列表推导式: 优点:是将所有的值一次性加载到内存中,相比 ...
- 没搞清楚网络I/O模型?那怎么入门Netty
微信搜索[阿丸笔记],关注Java/MySQL/中间件各系列原创实战笔记,干货满满. 本文是Netty系列笔记第二篇 Netty是网络应用框架,所以从最本质的角度来看,是对网络I/O模型的封装使用. ...
- 【排序基础】1、选择排序法 - Selection Sort
文章目录 选择排序法 - Selection Sort 为什么要学习O(n^2)的排序算法? 选择排序算法思想 操作:选择排序代码实现 选择排序法 - Selection Sort 简单记录-bobo ...
- 屏蔽每分钟SSH尝试登录超过10次的IP
屏蔽每分钟SSH尝试登录超过10次的IP 方法1:通过lastb获取登录状态: #!/bin/bash DATE=$(date +"%a %b %e %H:%M") #星期月天时分 ...
- service自动发现,yaml文件管理内外部端口访问
service服务发现 [root@k8s-master ~]# vim busybox-5d4f595646-dzjv4.yaml apiVersion: v1 kind: Pod metadata ...
- linux搭建简单samba服务器
1.安装需要的软体 yum install -y samba samba-client samba-common 2.创建samba需要的本地用户,创建samba服务使用的目录 Linux系统文件的读 ...