C++实例讲解四种类型转换的使用

目录
  • C++类型转换
    • C语言风格的转换
    • C++风格的类型转换
      • static_cast
      • reinterpret_cast
      • const_cast
      • dynamic_cast
  • 小结

C++类型转换

C语言风格的转换

C语言提供了自己的一套转换规则,有好处也有坏处。

C语言的风格:(type_name)expression;

C语言提供了隐式类型转换和显式类型转换。显式类型转换一般也叫做强转,隐式类型转换编译器完成,如果转换不了就报错。

而C语言类型转换的风格好处就是简单,缺陷比如转换的可视性差,显式类型转换的写法就只有一种,难以精准的跟踪错误。

char ch=1.1,char ch=1在.cpp下都是合法的,这就是隐式类型转换,C语言下如果把一个结构体给int就会报错,因为编译器不知道怎么去转,C++下可以通过实现operator int()实现类型转换或者提供合适的构造函数完成隐式类型转换,下面以在.cpp中实现operator int()为例

下面这段代码由于隐式类型转换导致了死循环

C语言的类型转换其实已经足够完成需求了,但是可视性不太好,比如你不能在代码库中搜索它(就一对括号怎么去搜索),所以C++提供了一套类型转换,相当于语法糖了,此外还会进行一些编译性检查(比如dynamic_cast转换失败则返回空指针)。但其实作用都是一样的。

C++风格的类型转换

C++标准为了增加类型转换的可见性,提供了四种类型转化的方式。

static_cast

静态类型转换,进行相关类型的转换,但不能转换两个不相关的类型(即编译器看到这个转换是行不通的就会报错)。

static_cast < type-id > ( expression )

int main()
{
	double a = (int)5.5 + 5.3;//结果是10.3
	double b = static_cast <int>(5.5) + 5.3;
	cout << "a: " << a << endl;
	cout << "b: " << b << endl;
	return 0;
}

转换不相关的类型:

reinterpret_cast

很暴力的一个操作符,由英文直译过来就是重新解释的转型。白话就是将一段内存重新解释。

网上看到很多大佬的理解,这里借用或掺杂自己的思想:static_cast是做类型能做的转换,不行编译器就报错,告诉你这样是不合理的,reinterpret_cast则是就算不能转换编译器你也别报错,我心里有数。由于reinterpret_cast本质上是一个编译器指令,所以实际动作完全取决于编译器,失去了移植性。

暴力归暴力,但也是合理范围内的,比如你把一个结构体硬塞给int肯定是不行的,但是把结构体指针重新解释为int那是一点问题没有。

此外reinterpret_cast重新解释的办法是把那一块内存的比特位全部复制下来重新解释。

下面的例子把一个结构体指针解释为int再加上5.3。

struct Test
{
	int a;
};
int main()
{
	Test* t = new Test;
	double c = reinterpret_cast <int>(&t) + 5.3;
	cout << c << endl;
	return 0;
}

const_cast

删除变量的const属性,一般和指针或引用连用

int main()
{
	const int a = 1;//a是常变量,在栈上
	int* p = const_cast<int*>(&a);
	*p = 2;
	cout << a << endl;
	cout << *p << endl;
	return 0;
}

volatile const int a=1;//打印的a就会是2

volatile后编译器对访问该变量的代码不再优化。比如上面那句代码打印1就是因为编译器优化,读取的a是从寄存器中读取的,而不是内存。

多线程中也有很多关于 volatile的应用。

dynamic_cast

dynamic_cast,安全的向下转型。

多态的转换中向下转型(父类转为子类)用dynamic是安全的,但是父类必须有虚函数,否则编译报错,且只能用于指针或引用。

向上转型,子类给父类,发生切割,不需要转换。

向下转型,父类地址给子类指针,需要类型转换,由于是类型是子类指针,但是给的地址是父类的,如果用指针去访问子类独有的数据可能就会造成越界,然后程序就可能崩了,所以此时就需要dynamic_cast进行转换了,因为dynamic_cast会检查父类指针是否指向的是这个子类,如果是父类说明可能带来一些安全问题,会转换失败返回空指针,反之则实现转换。

理解向下转型不安全有个例子:男人是人,但人不一定是男人(男人派生自人,男人的指针=(男人类型的指针强转)人的地址,此时如果通过男人指针去调用男人自己独有的特性就是越界,因为实际上拿到的是人的地址,并没有存储男人的特性,也可以从空间大小上来解释,人是父类,空间更小,男人是子类,空间更大,给的是小空间,却有了访问大空间的能力,所以可能造成越界,所以是不安全的)

此外在一个父类有多个子类且需要类型转换时,dynamic_cast也能起到作用,举个例子

//父类是Entity,子类是Player和Enemy, e,player,enemy分别表示他们对应的实例化对象
Entity* p=&player;
Enemy* p1=(Enemy*)p;//向下转型需要强转,这样搞就出问题了,p明明指向的是一个player,现在类型为Enemy的指针居然指向了一个Player的对象,如果对其内存进行了操作,那后果是不可预料的。

父类指针一开始指向一个父类对象,再给到子类类型的指针,存在越界的风险,如果为了保证安全则需要检查。

父类的指针指向子类对象(向上转型),再给到子类指针,合理。

所以建议使用dynamic_cast,因为可以保证安全, 转换失败返回空指针(NULL)。

dynamic_cast的底层与RTTI有关,借助RTTI拿到类型信息,所以dynamic_cast更像一个函数,因为不是编译指令,所以会带来一些性能的损失。

RTTI 是“Runtime Type Information”的缩写,意思是运行时类型信息。RTTI存储了所有类型运行时的类型信息,增加了开销但是可以让我们做更多的操作。dynamic_cast的底层就是借助了RTTI+匹配,具体的不太了解。VS可以关闭RTTI,但是也就不能用dynamic_cast了

下面给一个代码例子

class Entity
{
public:
	virtual void Print() {};//dynamic_cast使用的前提必须是父类有虚函数
};
class Player:public Entity
{
};
class Enemy :public Entity
{
};
void Check(void* p)
{
	if (p)
	{
		cout << "转换成功" << endl;
	}
	else
	{
		cout << "转换失败" << endl;
	}
}
int main()
{
	Entity* e = new Entity();
	Entity* actuallyPlayer = new Player();//向上转型
	//安全的向下转型
	Player* player =(Player*)actuallyPlayer;//向下转型需要转换类型
	Player* player2 = dynamic_cast<Player*>(actuallyPlayer);
	Check(player2); cout << endl;
	//不安全的向下转型
	Player* player3 = (Player*)e;
	Player* player4 = dynamic_cast<Player*>(e);
	Check(player4); cout << endl;
	Entity* actuallyEnemy = new Enemy();
	Player* player5 = dynamic_cast<Player*>(actuallyEnemy);
	Check(player5); cout << endl;
	return 0;
}

dynamic也常常利用返回值是否是空指针来判断指针具体指向谁。

用dynamic_cast的地方其实也可以用static_cast,不过static_cast不会进行安全检查,如果你很清楚其指向,并且在安全的前提下,为了减少程序开销那可以考虑用static_cast

小结

  • static_cast用于相关类型的转换
  • reinterpret_cast用于重新解释内存(很暴力,用的时候心里要有数)
  • const_cast常用来取出const属性,常与指针连用来修改const变量的值
  • dynamic_cast,在多态里提供安全的向下转换(转换不安全就返回空指针,只要对返回的指针进行判断我们就能知道此次转换安不安全了)

到此这篇关于C++实例讲解四种类型转换的使用的文章就介绍到这了,更多相关C++类型转换内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++强制类型转换的四种方式

    目录 1 C++类型转换本质 1.1 自动类型转换(隐式) 1.2 强制类型转换(显式) 1.3 类型转换的本质 1.4 类型转换的安全性 2 四种类型转换运算符 2.1 C语言的强制类型转换与C++的区别 3 static_cast 4 reinterpret_cast 5 const_cast 6 dynamic_cast 6.1 向上转型(Upcasting) 6.2 向下转型(Downcasting) 1 C++类型转换本质 1.1 自动类型转换(隐式) 利用编译器内置的转换规则,或者用

  • C++图文并茂讲解类型转换函数

    目录 一.类型转换函数(上) 1.再论类型转换 2.问题 3.再论构造函数 4.另一个视角 5.编译器的行为 6.小结(上) 二.类型转换函数(下) 1.类型转换 2.编译器的行为 3.注意事项 4.小结(下) 一.类型转换函数(上) 1.再论类型转换 标准数据类型之间会进行隐式的类型安全转换 转换规则如下: 下面来看一个有趣的隐式类型转换: #include <iostream> #include <string> using namespace std; int main()

  • C++超详细讲解强制类型转换

    目录 1 C 强制类型转换 2 C++ 强制类型转转 1 C 强制类型转换 C 方式的强制类型转换的用法如下代码所示: (Type)(Expression) Type:需要转换成的类型 Expression:对其进行转换 e.g. int v = 0x12345; // 将 int 类型的变量转换成 char 类型 char c = char(v); C 方式的强制类型转换存在如下问题: 过于粗暴:任意类型之间都可以进行转换,编译器很难判断其正确性 typedef void(PF)(int);

  • C++类型转换运算符详解

    目录 老式显式类型转换 c++的显示类型转换 为什么要有新的类型转换 具体应该使用哪种转换 static_cast运算符 dynamic_cast运算符 const_cast运算符 reinterpret_cast运算符 老式显式类型转换实际的转换方式 总结 老式显式类型转换 (类型)表达式 c风格的强制类型转换 类型(表达式) 函数式的强制类型转换 1,最开始使用的是c风格的类型转换,但是为了能够使类型转换看起来更像是一个函数调用,因此引入了函数式的类型转换.函数式的类型转换能够像使用一个函数

  • C++ 的类型转换详解

    目录 一.C++ 类型转换 1.静态类型转换 1.语法格式 2.转化规则 2.重解释类型转换 1.语法格式 2.转化规则 3.常类型转换 1.语法格式 2.语法规则 3.const 常变量(补充) 4.动态类型转换 1.语法格式 总结 一.C++ 类型转换 1.静态类型转换 1.语法格式 static_cast<目标类型> (标识符) 2.转化规则 在一个方向上可以作隐式转换,在另外一个方向上就可以作静态转换. int a = 10; int b = 3; cout<<static

  • C++简明讲解类型转换的使用与作用

    目录 一.C语言中的强制类型转换 二.C语言强制类型转换存在的问题 三.C++ 中的类型转换 四.小结 一.C语言中的强制类型转换 转换的语法如下: (Type) (Expression) Type(Expression) 下面看一段C语言中粗暴的类型转换的代码: #include <stdio.h> typedef void(PF)(int); struct Point { int x; int y; }; int main() { int v = 0x12345; PF* pf = (PF

  • C++算术运算符与类型转换

    目录 1.算术运算符 2.优先级 3.类型转换 初始化和赋值时的转换 使用花括号进行转换 4.表达式中转换 5.强制类型转换 1.算术运算符 C++当中提供5种基础的算术运算符:加法.减法.乘法.除法和取模. 我们来看下代码: int a = 10, b = 3; cout << a + b << endl; // 13 cout << a - b << endl; // 7 cout << a * b << endl; // 30

  • C++的类型转换(强转)你了解吗

    目录 静态类型转换 动态类型转换 常量转换 重新解释转换 总结 静态类型转换 关键字: static_cast 1,允许内置数据类型之间的转换 char a = 'a'; double b = static_cast<double>(a); cout << b << endl;//97 return 0; <>中是转后的数据类型.()中是要转的变量名称. 2,允许子类和父类之间指针或者引用的转换 向上类型转换是安全的.(子转父) 向下类型转换是不安全的.(父

  • C++ 强制类型转换详解

    目录 一.C强制转换 二.C++强制转换 1.static_cast 静态转换(编译时检查) 2.const_cast 常量转换 3.reinterpret_cast 重新解释转换 4.dynamic_cast 动态转换(运行时检查) 三.要点总结 一.C强制转换 C语言中的强制转换主要用于普通数据类型.指针的强制转换,没有类型检查,转换不安全, 语法为: (type-id)expression//转换格式1 type-id(expression)//转换格式2(基本已经不用了) 二.C++强制

  • C++实例讲解四种类型转换的使用

    目录 C++类型转换 C语言风格的转换 C++风格的类型转换 static_cast reinterpret_cast const_cast dynamic_cast 小结 C++类型转换 C语言风格的转换 C语言提供了自己的一套转换规则,有好处也有坏处. C语言的风格:(type_name)expression; C语言提供了隐式类型转换和显式类型转换.显式类型转换一般也叫做强转,隐式类型转换编译器完成,如果转换不了就报错. 而C语言类型转换的风格好处就是简单,缺陷比如转换的可视性差,显式类型

  • C++中的四种类型转换

    1 引子 这篇笔记是根据StackOverflow上面的一个问题整理而成,主要内容是对C/C++当中四种类型转换操作进行举例说明.在之前其实对它们都是有所了解的,而随着自己在进行总结,并敲了一些测试示例代码进行验证之后,对它们的理解又深刻了一些. 总所周知,在C++ 当中引入了四种新的类型转换操作符:static_cast, dynamic_cast, reinterpret_cast,还有const_cast.就自己见过的一些C++代码当中,它们的使用其实并不普遍.不少程序员依然乐于去使用C-

  • 一起聊聊C++中的四种类型转换符

    目录 一:背景 二:理解四大运算符 1. const_cast 2. reinterpret_cast 3. dynamic_cast 3. static_cast 一:背景 在玩 C 的时候,经常会用 void* 来指向一段内存地址开端,然后再将其强转成尺度更小的 char* 或 int* 来丈量一段内存,参考如下代码: int main() { void* ptr = malloc(sizeof(int) * 10); int* int_ptr = (int*)ptr; char* char

  • 详解C++中常用的四种类型转换方式

    目录 1.静态类型转换:static_cast(exp) 2.动态类型转换:dynamic_cast(exp) 3.常类型转换:const_case(exp) 4. 解释类型转换: reinterpret_cast(exp) 1.静态类型转换:static_cast(exp) 1.1静态类型转换主要用于两种转换环境 1.1.1 C++内置类型的转换:与C风格强转类似. 与c相同的地方: #include <iostream> using namespace std; int main() {

  • C++ RTTI与4种类型转换的深入理解

    前言 RTTI 是 Run Time Type Information 的缩写,从字面上来理解就是执行时期的类型信息,其重要作用就是动态判别执行时期的类型. 并不是说这篇文章是RTTI,和用于RTTI的四种类型转换,而是介绍RTTI,再介绍一下4种类型转换,因为RTTI有用到其中一种类型转换,所以相当于两篇文章写在一起. 实际上 RTTI 用到的是typeid() 和 dynamic_cast(). 为什么会有RTTI? C++是一种静态类型语言,其数据类型是在编译期就确定的,不能在运行时更改.

  • 浅谈C++为什么非要引入那几种类型转换

    众所周知C++关于类型转换引入了四种方式: static_cast const_cast dynamic_cast reinterpret_cast 为什么要引入这几种类型转换,它与C语言中的强制类型转换有什么区别? 这四种类型转换分别应用在什么场景? C++为什么要引入这几种强制类型转换? 我们都知道C++完全兼容C语言,C语言的转换方式很简单,可以在任意类型之间转换,但这也恰恰是缺点,因为极其不安全,可能不经意间将指向const对象的指针转换成非const对象的指针,可能将基类对象指针转成了

  • AJAX跨域请求数据的四种方法(实例讲解)

    由于浏览器的同源策略 ajax请求不可以接收到请求响应回来的数据 请求数据需要调用浏览器的内置构造函数 XMLHttpRequest() 进行 实例对象 var xhr = new XMLHttpRequest(); 注意点 在IE8之前支持的 ActiveXobject("Microsoft.XMLHTTP");  记住要进行兼容处理哦  在这里我就不写了 通过该对象进行获取 获取数据的四种状态  xhr.readyState 该属性保存着请求数据的几种状态 1.xhr.open(请

  • Android 常见的四种对话框实例讲解

    1.对话框通知(Dialog Notification) 当你的应用需要显示一个进度条或需要用户对信息进行确认时,可以使用对话框来完成. 下面代码将打开一个如图所示的对话框: public void click1(View view) { AlertDialog.Builder builder = new Builder(this); builder.setTitle("工学1号馆"); builder.setIcon(R.drawable.ic_launcher); builder.

  • js表格排序实例分析(支持int,float,date,string四种数据类型)

    本文实例讲述了js表格排序的方法.分享给大家供大家参考.具体如下: <html> <head> <title>SortTable2</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <script type="text/javascript"> var k=0; /**//*

随机推荐