C++进阶:C++类型转换

在C语言中,转换的可视性比较差,所有的转换形式都是以一种相同形式书写,难以跟踪错误的转换
转换使用场景:
(1)对对象(变量)进行初始化;
(2)对对象(变量)进行赋值;
(3)传参;
(4)返回值接收;

  • static_cast
    static_cast用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用static_cast,但它不能用于两个不相关的类型进行转换(相当于C语言中隐式类型转换)
    例如:
double d = 12.34;
int a = static_cast<int>(d);
  • reinterpret_cast
    从底层比特位层面进行转换,类似于C语言显式类型转换,例如:
double d = 1.34;
int* ptr = reinterpret_cast<int*>(&d);
  • const_cast
    const_cast最常用的用途就是删除变量的const属性,方便赋值
    例如:
const int c = 2;
int* p = const_cast<int*>(&c);//删除const属性,方便赋值
  • dynamic_cast
    用于将一个父类对象的指针转换为子类对象的指针或引用(动态转换)
    向上转型:子类对象指针->父类指针/引用(不需要转换,赋值兼容规则) 向下转型:父类对象指针->子类指针/引用(用dynamic_cast转换是安全的)
    注意: 1. dynamic_cast只能用于含有虚函数的类 2. dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0
    例如:
class Base
{
public:
	virtual void func()
	{
		cout << "Base::func()" << endl;
	}
protected:
	int _b;
};
class Derived :public Base
{
public:
	void funcD()
	{
		cout << "Derived::funcD()" << endl;
	}
protected:
	int _d;
};
void fun(Base* pa)
{
	pa->func();//实现多态
	// dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回
	Derived* pb1 = static_cast<Derived*>(pa);
	Derived* pb2 = dynamic_cast<Derived*>(pa);

	cout << "pb1:" << pb1 << endl;
	cout << "pb2:" << pb2 << endl;
}
int main()
{
	Base b;
	Derived d;
	//赋值兼容规则
	b = d;
	Base* pb = &d;
	Base& rb = d;
	Derived* pd = dynamic_cast<Derived*>(&b);//类的继承体系中必须有虚函数才能使用这种转换
	fun(&b);
	fun(&d);
}

最终的运行结果是:
在这里插入图片描述
将基类对象b传入函数fun中,使用static_cast可以成功转换,但是使用dynamic_cast不可以成功转换,第二次将子类对象传入,都可以成功转换;
此时pa是一个基类指针,不能调用子类中的成员函数,只能调用基类的成员函数,如果想要调用子类的成员函数,只能将pa转化为子类的指针,如果pa真正指向的是一个子类对象,代码是安全的,如果pa指向的是一个基类对象,代码不安全,dynamic_cast会进行检查,如果不安全返回空;
注意:强制类型转换关闭或挂起了正常的类型检查,每次使用强制类型转换前,程序员应该仔细考虑是否还有其他不同的方法达到同一目的,如果非强制类型转换不可,则应限制强制转换值的作用域,以减少发生错误的机会。强烈建议:避免使用强制类型转换

  • explicit
    explicit关键字阻止经过转换构造函数进行的隐式转换的发生
    例如:
class Date
{
public:
	explicit Date(int year)
		:_year(year)
		, _month(1)
		, _day(1)
	{
		cout << "Date::Date(int)" << endl;
	}
	Date& operator=(const Date& d)
	{
		if (this != &d)
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
			return *this;
		}
	}
	~Date()
	{
		cout << "Date::~Date()" << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1(2019);
	//1、用单参构造函数,用2020构造一个临时对象
	//2、用构造好的临时对象给d1赋值
	//3、赋值结束后,临时对象将被销毁
	//因此这种转换是正确的,如果不是单参构造函数,这里就是错误的,
	//可以使用explicit关键字来阻止经过转换构造函数进行的隐式转换的发生
	//d1 = 2020;//错误
	return 0;
}

为什么C++需要四种类型转换?
C风格的转换格式很简单,但是有不少缺点的:

  1. 隐式类型转化有些情况下可能会出问题
  2. 显式类型转换将所有情况混合在一起,代码不够清晰
  • RTTI
    RTTI:Run-time Type identification的简称,即:运行时类型识别。
    C++通过以下方式来支持RTTI:
    (1)typeid运算符
    (2)dynamic_cast运算符
    源代码(github):
    https://github.com/wangbiy/C-3/tree/master/test_2019_11_19/test_2019_11_19
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值