C++笔记 —— 强制类型转换
c++中提供了4种强制类型转换
static_cast,reinterpret_cast,const_cast,dynamic_cast
在c语言种提供了原始的强制类型转换方式,即直接使用类型名转换。比如要将int类型变量a转换成double类型变量则可以写成(double)a。但是这种方式会存在一定问题:
无法检索全文中所有出现了类型转换的地方,在检查程序时会有一定的不方便。
无法区分不同应用场景和不同风险的类型转换
c++中提供的4种强制类型转换都可以用统一的下标_cast检索,而且四种强制类型转换有不同功能,分别能在不同场景中使用
1.const_cast
对于一个被const限定的任意类型T的变量a,const_cast有两种功能。一是产生一个没有被const限定的a的引用,二是产生一个没有被const限定的T*类型的指针,并且该指针指向a。用户可以使用该引用或者该指针修改a的值,但是仍然无法通过a本身修改a的值。
1 void test_const_cast(){ 2 const string s = "hello world"; 3 string & s1 = const_cast<string &> (s); 4 string * ptrs = const_cast<string *> (&s); 5 6 //s[0] = 'a'; //编译报错,s本身还是不可以被修改 7 s1[1] = 'b'; // 编译通过 8 (*ptrs)[2] = 'c'; //编译通过9 }
2.static_cast
static_cast用于执行“低风险”的类型转换,所谓低风险,一般就是指整数,浮点数,字符之间的转换,不能用于整型和指针的转换,也不能用于不同类型的指针或者不同类型的引用之间的转换。但是,如果是自己实现的类,类中重载了类型转换运算符,就可以使用static_cast进行转换。
1 class A{ 2 public: 3 operator char*(){return nullptr;} 4 }; 5 6 void test_static_cast(){ 7 A a; 8 double b = 100.6; 9 int c = static_cast<int>(b); // 编译通过 10 char d = static_cast<char>(b); //编译通过 11 char* e = static_cast<char*>(b); // “高风险”的类型转换,报错 12 char* e = static_cast<char*>(a); // 自定义类中重载的类型转换,不会报错 13 }
3.reinterpret_cast
reinterpret_cast能够提供的转换方式最多,常用的有三种:1.任意两个指针类型之间的转换(包括函数指针)2.static_cast只能提供整型,浮点型,字符型之间的转换,reinterpret_cast可以提供这三种类型到他们的引用类型之间的转换,比如从char转换到double& 3.从指针类型到整型的转换。注意reinterpret_cast做的是把被转换的目标的每一个比特逐个拷贝到目的地中去,所以应该注意被转换类型的存储大小应该小于等于转换后类型的存储大小。否则不能完成转换。
1 typedef int (*ptr1)(int, int*); 2 typedef vector<char>* ptr2; 3 4 void test_reinterpret_cast(){ 5 /*第一种使用方式*/ 6 ptr1 p1; 7 ptr2 p2 = reinterpret_cast<ptr2> (p1); 8 /*第二种使用方式*/ 9 char a; 10 double& b = reinterpret_cast<double&> (a); 11 /*第三种使用方式*/ 12 ptr1 p3; 13 long long c = reinterpret_cast<long long> (p3);//使用long long是保证有足够的空间进行逐个比特的复制 14 }
4.dynamic_cast
dynamic_cast是实际运用中运用的最多的一种强制类型转换,它作用于将多态基类的指针或者引用转换成派生类的指针或者引用。此处有两点需要注意:一,必须是多态基类,也就是说在基类中必须定义了虚函数。二,dynamic_cast是一种能够自动检查转换安全性的强制类型转换。对于基类的指针,只有当该指针确实指向派生类的对象时,才能使用dynamic_cast将其转换成派生类指针。如果仍然指向基类对象,类型转换结果会返回NULL
1 class Base{ 2 public: 3 virtual ~Base(){}//基类中必须存在至少一个虚函数 4 }; 5 6 class Derived:public Base{}; 7 8 void test_dynamic_cast(){ 9 Base b; 10 Derived d; 11 Base* bptr1 = &b;//基类指针指向基类对象 12 Base* bptr2 = &d;//基类指针指向派生类对象 13 Derived* dptr1 = dynamic_cast<Derived*> (bptr1);//转换结果dptr1 == NULL 14 Derived* dptr2 = dynamic_cast<Derived*> (bptr2);//成功转换 15 16 Base& bquote = b; 17 Derived& dquote = dynamic_cast<Derived&> (bquote);//将基类的引用转换成派生类的引用 18 }
最后说明一下,类型转换永远是产生一个和自己一摸一样的副本,对副本进行类型转换,自己是不会改变的。