C++中的四种动态类型转换


在C语言中,强制类型的转换方式很简单,通过Type a = (Type)b即可,但是这样有两个比较明显的缺点:一是转换方式过于随意,可以在指针和整数之间进行转换,这是比较危险的操作;二是这样的转换方式在多括号的情况下不够清晰和直接,进而C++推出了自己的转换方式来改善这两种情况。C++显式类型转换有四种const_cast、static_cast、dynamic_cast、reinterpreter_cast,四种转换方式各有用途,需要针对不同情况选取不同的转换方式。

static_cast

static_cast是一种最常用的转型方式,我们可以在日常转型操作中首先尝试使用它,可能在很多场景中不需要它也能够隐式的完成转型操作,但是我们还是尽可能的将转型操作显式的表现出来。

可以完成以下类型的转换

  • 基本类型的转换(char转int,int转float之类)
  • void类型空指针转其他类型空指针
  • 任意类型转void类型指针
  • 父类到子类的转换(不保证正确)
  • 子类到父类的转换(保证正确)

注意:static_cast不能转换掉expression的const、volatile、或者__unaligned属性

const_cast

用于将const变量转换为非const变量,这是其他任何转换类型所没有的功能。需要注意两个点

  1. 去除const属性不是对于最初的const对象来说,修改最初的const对象仍旧是未定义的,去除const属性是指从引用或指针的方式来去除const属性。
  2. const_cast只适用于指针或者引用方式
#include <iostream>
using namespace std;

class A
{
public:
	void print() { cout << "hello" << endl; }
	void print() const { cout << "world" << endl; }
};

int main(){
    const int a=100;
    cout << &a << "  :  " << a << endl;
    int &b = const_cast<int&>(a);
    b = 110;
    cout << &b << "  :  " <<  b << endl;
    int *pa = const_cast<int*>(&a);
    *pa = 120;
    cout << pa << "  :  " << *pa << endl;
    cout << &a << "  :  " << a << endl;
    cout << &b << "  :  " <<  b << endl;
    
    A a;
	a.print();
	const A b;
	b.print();
	A& ref = const_cast<A&>(b);
	A* ptr = const_cast<A*>(&b);
	ref.print();
	ptr->print();
}

输出:
0x7ffcd8468304  :  100
0x7ffcd8468304  :  110
0x7ffcd8468304  :  120
0x7ffcd8468304  :  100
0x7ffffe03f164  :  120
hello
world
hello
hello

这里明明地址一样,为什么a和b,*pa的值会不一样呢?

答:a其实用const修饰后是一个常量,在预编译阶段,常量会被真实数值替换,所以并不是cout << a << endl;而是cout << 100 << endl;

dynamic_cast

dynamic_cast转换主要用于多态方面的转换,例如父类与子类之间的互相转换。在转换过程中如果能够成功转换就返回目标类型的指针,如果不行的话就返回空指针(用指针方式转换)或者抛出异常(用引用方式转换)。在进行upcast时,static_cast和dynamic_cast具有相同的效果;但在downcast(向下转换,也就是父类向子类转换)时,dynamic_cast相对于static_cast有一个类型检查,相对来说更加安全。另外需要注意的是:

  1. 如果子类不是通过public继承父类的话,那么转换会失败。这是因为父类的public成员因为private继承变成了private属性(对于子类而言),子类的指针无法访问父类中的非private成员,就会出现转换失败的问题
class A {
private:
	int a;
public:
	A(int a_) :a(a_) {}
	virtual void vprintfself(void) {
		std::cout <<"a"<<this->a<<std::endl;
	}
};
class B: public A {
private:
	int b;
public:
	B(int a_,int b_) :A(a_) { b = b_; }
	void vprintfself(void) {
		std::cout <<"b "<<this->b<< std::endl;
	}
};
int main()
{

	A* a = new A(2);
	B* static_p_a_B = static_cast<B*>(a);
	B* dymatic_p_a_B =dynamic_cast<B*>(a);//空指针
	static_p_a_B->vprintfself();
	dymatic_p_a_B->vprintfself();//报错

}

reinterpret_cast

interpret是解释的意思,reinterpret即为重新解释。这个转换几乎没什么条件限制,可以将任何指针类型转化为其他指针类型,少用为佳。

参考:

  1. https://zhuanlan.zhihu.com/p/83856596
  2. https://stackoverflow.com/questions/332030/when-should-static-cast-dynamic-cast-const-cast-and-reinterpret-cast-be-used
  3. https://www.jianshu.com/p/f2631fc62bde


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM