[C++]---C++几种类型转换

目录

 

C语言类型转换

为什么C++需要四种类型转换

C++类型转换

static_cast

reinterpret_cast

const_cast

dynamic_cast

explicit

C++中的RTTI机制

小结


C语言类型转换

//c语言类型转换
void testCast()
{
	//隐式类型转换

	//内置类型
	int i = 10;
	char c = i;

	
	//不支持转换,类型差别过大,但可以强转
	int *pi = &i;
	int i2 = pi;

	//强制转换,但像下面的这样没有意义
	int *pi = &i;
	int i2 = (int)pi;
}

缺陷: 转换的可视性比较差,所有的转换形式都是以一种相同形式书写,难以跟踪错误的转换

为什么C++需要四种类型转换

因为从上面可以看出C风格的转换格式很简单,但是有不少缺点的:

  1. 隐式类型转化有些情况下可能会出问题
  2. 显式类型转换将所有情况混合在一起,代码不够清晰

C++类型转换

标准C++为了加强类型转换的可视性,引入了四种命名的强制类型转换操作符:static_cast、reinterpret_cast、const_cast、dynamic_cast。

static_cast

static_cast用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用static_cast,但它不能用于两个不相关的类型进行转换。

void testCast2()
{
	int i = 10;
	//静态转换:static_cast
	//支持任何隐式类型转换  但它不支持两个不相关的类型进行强制转换
	char c = static_cast<char>(i);
	int i3 = static_cast<int> (pi);//报错  不支持两个不相关的类型进行强制转换
}

reinterpret_cast

reinterpret_cast操作符通常为操作数的位模式提供较低层次的重新解释用于将一种类型转换为另一种不同的类型  。

void testCast3()
{  

    int i = 10;
    //强制类型转换:reinterpret_cast
    //重新解释,用于将一种类型转换为另一种不同的类型
    int* pi = &i;
    int i2 = reinterpret_cast<int> (pi);

}

const_cast

常用于删除变量的const属性,方便赋值

 void testCast3()
 {  
    //const_cast: 去除变量的const属性
	const int ci = 20;
	const int* pci = &ci;
	//想要用 int*指针接收const int ci地址,可以使用 const_cast
	int* pci2 = const_cast<int*> (&ci);
	*pci2 = 30;
	cout << ci << endl;   //20
	cout << *pci2 << endl;//30
	cout << *pci << endl; //30
	cout << "adress" << endl;  //地址都一样 编译器做了优化
	cout << &ci << endl;   
	cout << pci2 << endl;
	cout << pci << endl; 
}    

dynamic_cast

dynamic_cast 用于将一个父类对象的指针转换为子类对象的指针或引用(动态转换)

  1. 向上转型:子类对象指针->父类指针/引用(不需要转换,赋值兼容规则)
  2. 向下转型:父类对象指针->子类指针/引用(用dynamic_cast转型是安全的)

注意: 1. dynamic_cast只能用于含有虚函数的类 2. dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0。

class A
{
public:
	virtual void fun()
	{
		cout << "A: fun()" << endl;
	}
};

class B:public A
{
public:
	virtual void fun()
	{
		cout << "B: fun()" << endl;
	}
};
void testCast4()
{
	B b;
	//切片  子类---》父类
	A a = b;
	A& rb = b;
	A* pb = &b;
	
	A aobj;
	B* pa = (B*)&aobj;//父类-》子类 需要强转
	B* pa2 = reinterpret_cast<B*> (&aobj);//可以强转但是不安全,容易访问越界。

	B* pa3 = dynamic_cast<B*> (&aobj);
	//static_cast没有类型安全检查,解引用可能会有问题。
	B* pa4 = static_cast<B*> (&aobj);//可以转换,没有语法错误,但是没有类型安全检查

	cout << pa << endl; //0032FA30 pa和pa2地址一样
	cout << pa2 << endl;//0032FA30
	cout << pa3 << endl;//不安全 00000000

	B* pb1 = dynamic_cast<B*> (pb);//pb: 指向子类对象的父类指针 因此可以转换是安全的
}

dynamic_cast 测试非多态

//非多态不可用
class C
{};

class D :public C
{};

void testCast5()
{
	//非多态不可使用 D 和 C没构成多态场景
	C c;
	D* pc = dynamic_cast<D*> (&c);
}

explicit

explicit关键字阻止经过转换构造函数进行的隐式转换的发生

//单参构造的隐式类型转换举例
class E
{
public:
	E(int a)
	:_a(a)
	{
		cout << "E(int a) " << endl;
	}
private:
	int _a;
};

int main()
{
	//单参构造的隐式类型转换
	E e = 10;//把一个整数类型赋给自定义类型,会支持   
	//实际上是它会用10调用构造函数创建一个匿名的E类型的对象,再把这个匿名对象赋给e 
	return 0;
}

实际上面的代码在执行时:它会用10调用构造函数创建一个匿名的E类型的对象,再把这个匿名对象赋给e。类型一致,赋值当然没错。

//多参构造的隐式类型转换举例
class E
{
public:
	E(int a, int b)
		:_a(a)
		{}
private:
	int _a;
};

int main()
{
	E e2 = 10, 20;
	return 0;
}

//explicit
class E
{
public:
	//explicit会阻止单参构造的隐式类型转换
	explicit E(int a)
		:_a(a)
	{
		cout << "E(int a) " << endl;
	}
private:
	int _a;
};

int main()
{
	//explicit关键字会阻止单参构造函数进行的隐式转换
	E e = 10;
	return 0;
}

C++中的RTTI机制

RTTI:Run-time Type identification的简称,即:运行时类型识别。

RTTI提供了以下两个非常有用的操作符:

  1. typeid操作符,返回指针和引用所指的实际类型。
  2. dynamic_cast操作符,将基类类型的指针或引用安全地转换为派生类型的指针或引用。

小结

因此使用强制转换方法的选择 如下

  • 去const属性用const_cast
  • 基本类型转换用static_cast
  • 多态类之间的类型转换用dynamic_cast
  • 不同类型的指针类型转换用reinterpret_cast

强制类型转换实际上 关闭或挂起了正常的类型检查,每次使用强制类型转换前,程序员应该仔细考虑是否还有其他不同的方法达到同一目的,如果非强制类型转换不可,则应限制强制转换值的作用域,以减少发生错误的机会。

强烈建议:避免使用强制类型转换

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值