[C++] C、C++类型转换

标题:[C++] C、C++类型转换

@水墨不写bug



目录

一、C的类型转换 

 二、C++的类型转换

1.static_cast(对应隐式类型转换)

2.reinterpret_cast(对应强制类型转换)

3.const_cast(对应强制类型转换中有风险的去掉const属性)

4.dynamic_cast


正文开始:

一、C的类型转换 

        C++的类型转换是对C语言类型转换的规范。

        在C语言中,发生的类型转换有两种:隐式类型转换和显示类型转换;如果赋值符号左右两侧的类型不同,或者形参与实参类型不匹配,或者返回值类型与接受返回值类型不一致时,就会发生类型转换。


隐式类型转换

        隐式类型转换编译器在编译阶段自动转换,如果可以转换,则没有提醒;如果不能转换,则编译失败。

显示类型转换

        需要我们自己手动处理,如用到“()”的强制类型转换。


         C语言的隐式类型转换我们在C语言阶段学习过,它遵循一定的规则,这里我们举一些例子:

        bool与整形的相互转换:非0的任意整形为真true,0为假false;true转为整形为1,false转为整形为0;

        浮点型与整形的相互转换:浮点数赋值给整形,只做近似处理。结果仅仅保留浮点数小数点之前的整数部分;整数赋值给浮点数,小数部分记为0,整数部分保留。

        无符号类型的超范围赋值:如果给一个无符号类型赋一个超出范围的值,结果是对无符号类型表示数值总数取模后的余数。

        有符号类型的超范围赋值:给有符号类型超范围赋值,结果未定义!


除此之外,内置类型与自定义类型之间相互转换 :内置类型可以通过构造函数隐式类型转换为自定义类型:单参数构造函数支持直接赋值,多参数构造函数支持用“{}”花括号赋值。

#include<iostream>
using namespace std;
class A{

public:
	A(int a = -1)
		:_a(a)
		,_b(a)
	{}

	int _a;
	int _b;
};
class AA{

public:
	AA(int a1 = -1,int a2 = -1)
		:_a(a1)
		, _b(a2)
	{}

	int _a;
	int _b;
};
int main()
{
	A aa1 = 1;//单参数构造函数支持直接用内置类型隐式类型转换
	
	AA aa2 = { 1,2 };//多参数构造函数可以使用花括号实现隐式类型转换

	return 0;
}

         自定义类型也可以隐式类型转换为内置类型,需要通过特定的成员函数实现:

这个成员函数是一个有着特殊实现语法的函数,实现的语法格式如下:

operator /*需要转换成的类型*/()
{
    //具体的实现没有限制,可以对这个对象内部的数据进行运算,最终返回结果即可
    return /*返回需要转换成的类型即可*/
}

 比如,实现将下面这个类型隐式类型转换为double:


class A
{
public:
	int _a;
	double _b;
};

 那么就需要实现这样的一个函数:(函数内部如何实现没有限制,只要实现了A到double类型的转换即可)

    operator double()
	{
		return _a + _b;
	}
	

于是,可以进行A到double的隐式类型转换了:
         


class A
{
public:
	A(int a = -1,double b = -1)
		:_a(a)
		,_b(b)
	{}
	operator double()
	{
		return _a + _b;
	}
	int _a;
	double _b;
};

int main()
{
	A aa1(4, 8.7);

	double f = aa1;
	//f 的值为 12.7
	return 0;
}

         自定义类型和自定义类型也是可以实现相互转换的,本质就是借助对应的构造函数:

class A{
public:
	A(int a = -1,int b = -1)
		:_a(a)
		,_b(b)
	{}
	const int get() const
	{
		return _a + _b;
	}
	int get()
	{
		return _a + _b;
	}
private:
	int _a;
	int _b;
};
class B{
public:
	B(int c = -1)
		:_c(c)
	{}
	B(const A& aa)
		:_c(aa.get())
	{}
	int _c;
};
int main()
{
	A aa = { 2,5 };
	B bb;

	bb = aa;//B提供了从A构造B的构造函数,所以可以实现A隐式类型转换到B
            
	cout << bb._c << endl;
    //  7
	return 0;
}

        强制类型转换也只是能将有一定关系的类型相互强制转换。相反,如果两个类型相差十分大,强制类型转换也无能为力。

缺陷:

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

 二、C++的类型转换

         注意C++是兼容C的,所以在C++程序中,也会出现C的类型转换。由于C的类型转换混合杂糅,难以区分,十分模糊,所以C++提出了自己的一套类型转换逻辑。

        这些类型转换是需要显示使用的,所以在掌控之中的类型转换时,用C++的类型转换能够使源码的逻辑性,可读性大大提高。标准C++为了使类型转换可视化,引入了四种类型转换操作符:

static_cast

reinterpret_cast

const_cast

dynamic_cast

这些类型转换操作符的使用方法如下:

1.static_cast(对应隐式类型转换)

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

        原来可以隐式类型转换的,就可以使用static_cast进行转换。


int main()
{
	int a = 4;
	double b = static_cast<int>(a);
	cout << a << " " << b << endl;

	cout << "------------------" << endl;

	double d = 4.98;
	int f = static_cast<int>(d);
	cout << d << " " << f << endl;
	return 0;
}
4 4
------------------
4.98 4

 两种类型相差过大,根本不相关,无法类型转换:


class A
{
	int _a;
};
class B
{
	double _b;
};
int main()
{
	A a;
	B b = static_cast<A>(a);
	return 0;
}

2.reinterpret_cast(对应强制类型转换)

        原来需要进行强制类型转换的,需要用reinterpret_cast。

        比如:指针与整形的转换(数据的意义已经改变)

 

3.const_cast(对应强制类型转换中有风险的去掉const属性)

        const_cast最常用的用途就是删除变量的const属性,方便赋值。

void Test ()
{
    const int a = 2;
    int* p = const_cast< int*>(&a );
    *p = 3;
    cout<<a <<endl;
    cout<<*p<<endl;
}
2
3

        当我们运行上面这一段代码,就会发现两次输出是不同的,a和*p代表的值相同,但是为什么输出的值不同?

        原因在于编译器的优化,由于识别a为const,所以直接把a的副本当作const对待了,当a改变的时候,a的副本没有改变,所以输出a(其实是a的副本)仍然是原先的2,而*p(a本身)则已经改变 为3。

        如果想要不优化,需要在a的前面加上volatile关键字即可。


void Test()
{
    volatile const int a = 2;
    int* p = const_cast<int*>(&a);
    *p = 3;
    cout << a << endl;
    cout << *p << endl;
}
int main()
{
    Test();
}
3
3

4.dynamic_cast

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

        向上转型:子类对象指针/引用->父类指针/引用(不需要转换,赋值兼容规则)

        向下转型:父类对象指针/引用->子类指针/引用(用dynamic_cast转型是安全的)

        dynamic_cast 在运行时检查类型信息(RTTI,即运行时类型信息),以确保转换的安全性。如果转换是安全的(即基类指针或引用确实指向了一个派生类的对象),则转换成功;如果不是,则转换失败。对于指针类型的转换,失败时返回 nullptr;对于引用类型的转换,如果转换不安全,则会抛出一个 std::bad_cast 异常(但这通常不推荐用于引用类型的 dynamic_cast,因为异常可能导致程序终止)。 

注意:

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


完 ~

未经作者同意禁止转载

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

水墨不写bug

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值