C++ 强制类型转换

简言

        在C++中有时候两种类型需要相互转换,有可能是隐式转换也有可能是显示转换。隐式类型转换由编译器决定,能转就转。显示转换(强转)需要由用户自己决定。

隐式转换        

	double num = 3.14;
	int sum = num + 5;

         例如上面的例子,num是一个double型的数据,5是一个int型的数据,而sum是一个int型的数据。那么编译器遇到这种情况会怎么办呢?C++不允许两个不同类型的值相加,而是会先根据类型转换规则将运算对象的类型转换一致后再相加。上述的类型转换是自动执行的,所以称为隐式转换。隐式转换应该尽可能避免精度的损失,当算术运算表达式中既有整型类型的运算对象,又有浮点型类型的运算对象时,会将整形运算对象的类型转换为浮点型。所以上述的例子中,当double类型的num加上int类型的5时,编译器会将int型5转换为double类型的5相加得到double型结果8.14;然后用double型值8.14去初始化int型对象sum,这里会丢弃到小数点后的部分,用8去初始化对象sum。

        什么时候会发生隐式转换呢?往往在下面的几种情况会发生隐式转换:

        1、在条件中,非布尔值会转换成布尔值;

        2、在初始化过程中,初始值转化为变量的类型;

        3、在赋值语句中,右侧运算对象转换成左侧运算对象的值;

        4、如果算术运算或关系运算的运算对象有多个类型时,需要转换成同一种类型。

强制转换

        C++提供了四种强制转换的方式,分别是static_cast,dynamic_cast,const_ccast和reinterpret_cast四种。强制转换的形式为:cast-name<type>(expression),其中cast-name为四种强制转换方式的一种,type为将要转换的类型,expression是要转换的值。

static_cast

void test01()
{
	double num1 = 12.5;		
	int num2 = num1;		//隐式转换,编译器会警告提醒精度损失
	int num3 = (int)num1;	//C风格强制转换,不会提醒精度损失
	int num4 = static_cast<int>(num1);		//C++风格强制转换,不会提醒精度损失
}

void test02(void *p)
{
	int a = 10;
	double *ptr = static_cast<double*>(p);		//将void*指针转为double*类型指针
	int *p1 = &a;
	double *ptrD = static_cast<double*>(p1);	//不同类型的指针不能强转
}

      static_cast可用于隐式执行的任何转换,还可以用于转换指针,我们知道void *指针是可以指向任何指针类型的,但是相反不可以,我们就可以用static_cast强制转换成我们想要的指针类型。但是不同类型的指针之间是不可以直接转换的。还有static_cast不能去掉对象的底层const属性。什么是底层const呢?顶层const:顶层const表示指针本身是个常量,底层const:底层const表示指针所指的对象是个常量。

const_cast

        const_cast只能改变对象的底层const。

	const char *p;
	char *ptr = const_cast<char*>(p);

        将常量对象去掉常量性质,被称为去掉const性质。当我们去掉const性质后,就可以对该对象进行写操作了。

dynamic_cast

        dynamic_cast是一个运行时类型识别运算符,程序在运行时确定对象的类型。dynamic_cast用于将一个对象的指针或引用转换为另一个对象的指针或引用。一般是将父类对象的指针或引用转化为子类对象的指针或引用,反之也可将子类对象的指针或引用转化为父类对象的指针或引用(本身就可以,不需要强转)。

        所以一般使用格式就是:派生类指针 = dynamic_cast<派生类类型*>(基类指针);如果转换失败了就返回0。注意:dynamic_cast只适用于包含虚函数的类,dynamic_cast是为多态而准备的,dynamic_cast代码示例:

class Animal
{
public:
	virtual int getAge() const { return m_age; }
	virtual void show() { std::cout << "hello world!"; } //基类show函数
protected:
	int m_age;
};

class Cat :public Animal
{
public:
	virtual void show() { std::cout << "I am is a Cat!"; }	//派生类show函数
	void func() { std::cout << "I am so cute!"; }		//func函数不是虚函数!!!
};

int main()
{

	Animal* animal = new Cat();
	animal->show();
	if (Cat* cat = dynamic_cast<Cat*>(animal))
	{
		cat->func();
	}
	else
	{
		//强转失败
	}
}

        一般当我们使用基类指针指向一个子类对象时,可以通过虚函数重写来调用子类的虚函数。但我们使用dynamic_cast强制转换后将基类指针转换为派生类指针,就可以调用派生类的非虚函数func();

reinterpret_cast

        reinterpret_cast的意思是重新解释,它可以用于不同类型的指针之间转换,static_cast不可以。reinterpret_cast<type>(expression)中的type和expression的类型中必须有一个为引用或者是指针。同样reinterpret_cast不能改变const属性。

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

总结

        最后的结尾引用C++经典书籍对于强制转换的总结。强制类型转换干扰了正常的类型检查,因此我们强烈建议程序员避免使用强制类型转换。这个建议对于reinterpret cast 尤其适用,因为此类类型转换总是充满了风险。其他强制类型转换,比如 static cast 和dynamic cast,都不应该频繁使用。每次书写了一条强制类型转换语句,都应该反复斟酌能否以其他方式实现相同的目标。就算实在无法避免,也应该尽量限制类型转换值的作用域,并且记录对相关类型的所有假定,这样可以减少错误发生的机会。(C++Primer 5th)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值