C++那些细节--static_cast,dynamic_cast,const_casst,reinterpret_cast

恩,这四个cast,之前一直没怎么搞懂,在使用类型转化时仍然经常使用C风格的转化,而且之前的一次笔试题竟然考的就是这道题,好吧,我强迫症又犯了,一定要彻底搞懂...


一.概述

1.(typename)element:C风格的强制转化,貌似通吃,但是既然用了C++,还有分门别类的cast,是时候放弃这个了。

2. static_cast<typename>(element):通常转换,没有运行时的检测,在不知道用哪个的时候用这个就好了。

3. dynamic_cast<typename>(element) :动态转换,有运行时检测,通常在基类和派生类之间转换时使用。

4. const_cast<typename>(element):主要针对const和volatile的转换,去除const属性

5. reinterpret_cast<typename>(element):用于没有任何关联的类型转换,慎用


俗话说得好,实践是检验真理的唯一标准,要想清楚的知道每种转化会发生什么,最好的办法就是写个demo,而不是看别人的blog怎么写,自己就怎么说,这样印象不深刻,而且可能人云亦云,没有自己的想法。


二.static_cast

关于static_cast,最常用的一个转化,当我们不知道用哪个cast的时候,static_cast是最好的选择。但是这个转换没有运行时类型检查保证转换的安全性。允许任意的隐式转换以及相反的转换动作。具体的转化功能如下:
1.基本数据类型之间的转化,如Int转化为char之类的
2.void*类型的指针转化为其他类型的指针
3.其他类型的指针转化为void*类型的指针
4.子类指针转化为父类指针(向上转型,安全,不写static_cast也会发生隐式转换)
5.父类指针转化为子类指针(向下转型,不一定安全,如果调用子类特有字段属性会出错)

注意:
1.static_cast不能转换掉const,volitale属性
2.在基本的类型或者上下转型时,被转化的对象和要转化成的对象要类型一致,如果在两个不相干的类型中转化,会编译出错。

好的,下面是针对这5点的一个例子:

// C++Test.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;

class CastTestBase
{
public:
	CastTestBase(string n):name(n)
	{

	}

	~CastTestBase()
	{

	}

	void ShowBase()
	{
		cout<<"show base, name is : "<<name<<endl;
	}
private:
	string name;
};

class CastTestChild : public CastTestBase
{
public:
	CastTestChild(string n, string cn) : CastTestBase(n), childname(cn)
	{

	}

	~CastTestChild()
	{

	}

	void ShowChild()
	{
		cout<<"show child, name is: "<<childname<<endl;
	}
private:
	string childname;
};

void TestFunc1(int* num)
{
	cout<<"num is "<<*num<<endl;
}

void TestFunc2(void* pointer)
{
	cout<<"num is "<<(*static_cast<int*>(pointer))<<endl;
}

int _tmain(int argc, _TCHAR* argv[])
{
	//static_cast转换内置数据类型
	int a = 10;
	char b = static_cast<char>(a);

	//void*型指针转化为其他类型指针
	void* pointer = new int(1);
	TestFunc1(static_cast<int*>(pointer));

	//其他任何类型指针转化为void*型指针
	int* num = new int(2);
	TestFunc2(num);

	//子类指针转化为父类指针(安全,不写static_cast也可以执行隐式转换)
	CastTestBase* basePointer = static_cast<CastTestBase*>(new CastTestChild("child", "child"));
	basePointer->ShowBase();

	//父类指针转化为子类指针(不一定安全,如果调用子类特有的内容会出错)
	CastTestChild* childPointer = static_cast<CastTestChild*>(new CastTestBase("base"));
	//childPointer->ShowChild();//这样会出错的,父类并没有childname字段。而如果只调用函数没有问题,使用字段会出现问题
	childPointer->ShowBase();

	system("pause");
	return 0;
}

结果:
num is 1
num is 2
show base, name is : child
show base, name is : base
请按任意键继续. . .

//childPointer->ShowChild();//这样会出错的,父类并没有childname字段。而如果只调用函数没有问题,使用字段会出现问题
这句如果运行,会有问题,即编译不会出错,不会检查类型转换的问题,在运行时直接崩掉。


三.dynamic_cast

从字面上理解是动态转化,其实就是增加了运行时检查的机制,如果转化不对,在运行时会返回一个空指针,我们可以通过判断转化的结果是否为空来判断转化是否成功,而不会像static_cast一样直接崩掉。不过,既然加了运行时检查,在运行时肯定会有性能的损失。

dynamic_cast运用于下面的情况:
只能用于指针或者引用,主要用于执行带有安全检测的向上转型或者向下转型,不过向上转型可以有隐式转化,并且是安全的,所以主要是用于向下转型的检测。
1.基类有虚函数时,可以向上或者向下转型,在向下转型时可以判断转换是否能返回一个完整的对象,在运行时检测。如果有问题,返回一个空指针
2.基类没有虚函数时,只能进行向上转型,然而向上转型并不需要dynamic_cast,隐式转化也可以,否则编译出错。

// C++Test.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;

class CastTestBase
{
public:
	CastTestBase(string n):name(n)
	{

	}

	~CastTestBase()
	{

	}

	void ShowBase()
	{
		cout<<"show base in base, name is : "<<name<<endl;
	}

	virtual void ShowChild()
	{
		cout<<"show child in base"<<endl;
	}
private:
	string name;
};

class CastTestChild : public CastTestBase
{
public:
	CastTestChild(string n, string cn) : CastTestBase(n), childname(cn)
	{

	}

	~CastTestChild()
	{

	}

	virtual void ShowChild() override
	{
		cout<<"show child in child, name is: "<<childname<<endl;
	}
private:
	string childname;
};

int _tmain(int argc, _TCHAR* argv[])
{
	//子类指针转化为父类指针(安全,不写static_cast也可以执行隐式转换)
	CastTestBase* basePointer = dynamic_cast<CastTestBase*>(new CastTestChild("child", "child"));
	basePointer->ShowBase();
	basePointer->ShowChild();

	//父类指针转化为子类指针(不一定安全,如果调用子类特有的内容会出错)
	CastTestChild* childPointer = dynamic_cast<CastTestChild*>(new CastTestBase("base"));
	if (childPointer)//dynamic_cast的返回值可能是NULL,切记!!!
	{
		childPointer->ShowBase();
		childPointer->ShowChild();//这样会出错的,父类并没有childname字段。而如果只调用函数没有问题,使用字段会出现问题
	}
	else
		cout<<"dynamic_cast failed!"<<endl;
	

	system("pause");
	return 0;
}

结果:
show base in base, name is : child
show child in child, name is: child
dynamic_cast failed!
请按任意键继续. . .

这里,由于和上面static_cast一样的原因,showchilid本应该出错,但是在转化过程中,dynamic_cast判断出了转化会出问题,所以直接返回了一个空指针,让我们可以根据这个进行处理,就避免了程序直接莫名的崩溃...


四.const_cast

用于修改类型的const或者volatile属性,类型不会有变化,只是去掉前面的修饰符。

int _tmain(int argc, _TCHAR* argv[])
{
	const int a = 10;
	//a = 20;不能修改常量
	//int b = const_cast<int>(a);<>中的即要转化的对象必须是指针或者引用
	int* b = const_cast<int*>(&a);
	//int* b = &a;const int 类型的实体不能使用int*类型的指针指向
	*b = 20;
	cout<<*b<<endl;
	
	//int& c = a;非const引用不能引用const变量
	int& c = const_cast<int&>(a);
	c = 30;
	cout<<c<<endl;

	system("pause");
	return 0;
}


使用const_cast时要注意,const_cast并非直接修改变量,而是只能通过指针或者引用来去除const限定符,即 const_cast的<>中只能接受引用或者指针类型的对象。不能直接放入数据类型。转换之后仍然指向或者引用原来的对象,但是常量对象被转化为非常量对象。

C++有const类型,就是让我们不改变变量的内容,但是还是提供了去除这一个限制的方法,可见C++的灵活!!!



五.reinpreter_cast

这个最简单粗暴...甭管是啥,都能转。类型可以是指针,引用,基本数据类型,函数指针,或者成员指针。甚至可以将int转化为一个指针...这种转化根本不会检查转化的合理性,只是拷贝数据,强制转化。

这个东东还是慎用吧,如果他说什么都能干,感觉可能什么都干不好...还是术业有专攻的好...




参考链接:http://m.blog.csdn.net/blog/pizi0475/46794631

http://blog.csdn.net/starryheavens/article/details/4617637



  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值