C++四大显式类型转换

static_cast、dynamic_cast、reinterpret_cast、const_cast
详细参考《C++的设计和演化》。
最好不好使用C风格的强制类型转换。
他们都属于操作符,因此他们不属于任何的命名空间(namespace),也就不用包含任何的头文件就可以使用。

转换时期

static_cast:编译期转换。
reinterpret_cast:
const_cast:编译期转换。
dynamic_cast:运行期转换。

static_cast

格式:static_cast(expression)
说明:该运算符把expression转换成type类型,但是没有运行时类型检查来保证转换的安全性
为什么需要static_cast强制转换?
a) void指针转换为其他类型指针
b) 改变通常的标准转换
c) 避免出现可能多种转换的歧义

主要用法:
a) 用于类层次结构中基类和子类之间指针或引用的转换。进行上行转换(把子类的指针或引用转换成基类表示)是安全的,进行下行转换(把基类指针或引用转换成子类指针或引用)时,由于没有动态类型检查,所以是不安全的。
**为什么呢?**想一想,派生类继承基类的时候,子类是会拷贝父类的属性和方法,子类对象的大小肯定是大于等于父类对象的。本来父类的指针可以访问的空间是父类的空间,当父类指针指向子类对象的时候,你能访问的只能是从父类继承来的,这个没有问题吧?子类特有的属性和方法你是访问不了的。所以说你父类指针指向子类对象的时候,只能调用自己遗留给儿子的遗产,儿子的钱你看不到,也花不了。反过来也是,派生类指针指向父类的对象的时候,你这个指针能访问的空间肯定是大于等于你父类的。当你用这个指针访问超过父类的空间的时候不就相当于越界了么。这也是栈溢出的一个例子吧!
为什么是栈溢出呢?这里也简单说一下子,也是给自己强化记忆了。
用类去定义对象时,系统会为每一个对象分配存储空间。如果一个类包括了属性和方法,要分别为数据和函数的代码分配存储空间。按理说,如果用同一个类定义了10个对象,那么就需要分别为10个对象的属性和方法代码分配存储单元。显然,这样是不符合常理的,因为代码是不会被更改的,只有每个对象的属性是不一样的,因此你用一部分空间去放这个不会被更改的物质,所有对象共享这个,可以大大的节省空间,编译器这是如你所想,这么做的。因此每个对象所占用的空间只是该对象的属性(虚函数指针,基类指针也属于的哈!)所占用的存储空间,而不包括函数代码所占用的存储空间。
C++程序的内存内存格局通常分为四个区:全局区(静态区)、代码区、栈区、堆区(自由存储区),全局区存放全局变量,静态数据和常量,里面分两个区域,未初始化的和初始化的(bss,base segment和data段),**代码区:**所有的类成员函数和非成员函数代码存放在代码区;而运行函数而分配的局部变量、函数参数、返回数据、返回地址等存放在栈区;栈溢出或者说是越界?

b) 用于基本数据类型之间的转换,如把int转换成char,把int转换成enum这种转换的安全性也需要开发人员来保证。
c) 把void指针转换成目标类型的指针(不安全!)
d) 把任何类型的表达式转换成void类型。
注意:static_cast不能转换掉expression的const、volitale、或者_unaligned属性

dynamic_cast

格式:dynamic_cast(expression)
说明:该运算符把expression转换成type类型的对象,type必须是类的指针、类的引用或者void;如果type是类指针类型,那么expression也必须是一个指针,如果type是一个引用,那么expression也必须是一个引用。*

为什么需要dynamic_cast强制转换?
像博主所言,简单来说,当你无法使用virtual 函数的时候
废话比多说,上代码。骚年让你三行代码
荔汁:

// Employee.h
class Employee
{
	public :
	virtual int salary();
};

class Manager :public Employee
{
	public:
	int salary();
};

class Programmer:public Employee
{
	public:
	int salary();
};
class MyCompany
{
public:
void payroll(Employee *pe)
};
void MyCompany::payroll(Employee *pe){}

你希望增加一个bonus()成员函数,当你知道源代码的时候,很简单,增加虚函数。

// Employee.h
class Employee
{
public:
	virtual int salary();
	virtual int bonus();
};

class Manager:public Employee
{
public:
	int salary();
	itn bonus();
}

class Programmer::bonus(){}

payroll()通过多态来调用bonus()

class Mycompany
{
public:
	void payroll(Employee *pe);
};
void Mycompany::payroll(Employee *pe)
{
}

但是你现在的情况是,我们并不能修改源代码,怎么办?dynamic_cast华丽登场了!
在Employee.h中增加bonus()声明,在另一个地方定义此函数,修改调用函数payroll()。重新编译

class Employee
{
public:
	virtual int salary();
};
class Manager:public Employee
{
	public:
	int salary();
};
class Programmer:public Employee
{
public:
	int salary();
	int bonus();//直接在这里扩展
}

int Programmer::bonus()
{
}
class MyCompany
{
public:
void payroll(Employee *pe);
};
void MyCompany::payroll(Employee *pe)
{
	Programmer *pm = dynamic_cast<Programmer*>(pe);
	//如果pe实际指向一个Programmer对象,dynamic_cast成功,并且开始指向Programmer对象的起始处
	if(pm)
	{
	}
	else
	{
	}
}
/

shit没看懂!先记下来。为什么不能修改源码,他在头文件Programmer中声明了bonus()函数,然后类外定义,为什么不可以在Manager类中声明,然后定义?还是说都可以。还有 Programmer pm = dynamic_cast<Programmer>(pe);这一行不是pm指针是空的么。是空的,博主上面这一顿操作什么意思?为了证明下行转换是不行的?那你为什么说这个是需要dynamic_cast的场景。。。。
在这里插入图片描述

dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。
在类层次间的上行转换时,dynamic_cast和static_cast的效果是一样的;在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全,如果不适用dynamic_cast检查是不是子类,编译会弹窗崩溃。

另外需要注意的是:基类是要有虚函数的,否则会编译“基类需要时多态的”出错,static_cast没有这个限制,这是由于运行时类型检查需要运行时类型信息,而这个信息存在类的虚函数表中。只有定义了虚函数的类才有虚函数表,没有定义虚函数的类是没有虚函数表的。

reinterpreter_cast

格式:reinterpreter_cast(expression)
说明:type必须是一个指针、引用、算数类型、函数指针或者成员指针。他可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,再把该整数转换成原类型的指针,还可以得到原先的指针值)。

int *p;
char *pc = reinterpret_cast<char*>(p);

这样的转换过程非常危险,因为一旦在后面的程序中忘记pc指针指向的是一个int类型的数据,对其操作就会引起数据混乱的现象。reinterpret_cast很少使用,因为在reinterpret_cast本质上依赖于机器,要向使用reinterpret_cast必须设计的类型和编译器实现转换的过程都非常了解。

const_cast

格式:const_cast(expression)
说明:该运算符用来修改类型的const或volatile属性。除了const或volatile修饰之外,type和expression的类型是一样的。我认为,它就是可以使,可以使用常量给非常量赋值。

常量指针被转换成非常量指针,并且仍然指向原来的对象;常量引用被转换成非常量引用,并且仍然指向原来的对象;常量对象被转换成非常量对象。

#include<iostream>
using namespace std;
int main()
{
	const int b = 10;
	
	int  b2 = const_cast<int&>(b);
	b2 = 20;
	cout << b << endl;
	system("pause");
	return 0;
}

输出b为20

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值