c++强制类型转换
c++有四种强制类型转换方式,分别为:reinterpret_cast、const_cast、static_cast、dynamic_cast
reinterpret_cast
reinterpret_cast<type-id> (expression)
对象 必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以用于类型之间进行强制转换。
适用场景:改变指针或引用的类型、将指针或引用转换为一个足够长度的整形、将整型转换为指针或引用类型。
int *a = new int; double *d = reinterpret_cast<double *>(a);
const_cast
const_cast<type_id> (expression)
该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外, type_id和expression的类型是一样的。
需要特别注意的是const_cast不是用于去除变量的常量性,而是去除指向常数对象的指针或引用的常量性,其去除常量性的对象必须为指针或引用。
const int a = 10; const int * p = &a; *p = 20; //compile error int b = const_cast<int>(a); //compile error int *q = const_cast<int*>(p); //fine
下面举一个特殊的例子:
#include<iostream> using namespace std; int main() { const int a = 10; const int * p = &a; int *q; q = const_cast<int *>(p); *q = 20; //fine cout <<a<<" "<<*p<<" "<<*q<<endl; cout <<&a<<" "<<p<<" "<<q<<endl; return 0; } //输出: 10 20 20 // 002CFAF4 002CFAF4 002CFAF4
上例中常量指针p的值通过const_cast强制类型转换赋给了非常量指针q。但是q修改了其指向的值,而该值是常量数据a,此行为是未定义行为(ub),未定义行为的结果取决于编译器。
了解了const_cast的使用场景后,可以知道使用const_cast通常是一种无奈之举,同时也建议大家在今后的C++程序设计过程中一定不要利用const_cast去掉指针或引用的常量性并且去修改原始变量的数值,这是一种非常不好的行为。
static_cast
static_cast < type-id > (expression)
该运算符把expression转换为type-id类型,但没有运行时类型检查来保证转换的安全性。它主要有如下几种用法:
-
用于类层次结构中基类(父类)和派生类(子类)之间指针或引用引用的转换
-
进行上行转换(把派生类的指针或引用转换成基类表示)是安全的
-
进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的
-
-
用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。
-
把空指针转换成目标类型的空指针
-
把任何类型的表达式转换成void类型
注意:static_cast不能转换掉expression的const、volatile、或者__unaligned属性。
int a = 10; int b = 3; double result = static_cast<double>(a) / static_cast<double>(b);
dynamic_cast
dynamic_cast <type-id> (expression)
(1)其他三种都是编译时完成的,dynamic_cast是运行时处理的,运行时要进行类型检查。
(2)不能用于内置的基本数据类型的强制转换。
(3)dynamic_cast转换如果成功的话返回的是指向类的指针或引用,转换失败的话则会返回NULL。
(4)使用dynamic_cast进行转换的,基类中一定要有虚函数,否则编译不通过。
B中需要检测有虚函数的原因:类中存在虚函数,就说明它有想要让基类指针或引用指向派生类对象的情况,此时转换才有意义。
这是由于运行时类型检查需要运行时类型信息,而这个信息存储在类的虚函数表(关于虚函数表的概念,详细可见<Inside c++ object model>)中,
只有定义了虚函数的类才有虚函数表。
(5)在类的转换时,在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的。在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。
向上转换,即为子类指针指向父类指针(一般不会出问题);向下转换,即将父类指针转化子类指针。
向下转换的成功与否还与将要转换的类型有关,即要转换的指针指向的对象的实际类型与转换以后的对象类型一定要相同,否则转换失败。
在C++中,编译期的类型转换有可能会在运行时出现错误,特别是涉及到类对象的指针或引用操作时,更容易产生错误。Dynamic_cast操作符则可以在运行期对可能产生问题的类型转换进行测试。
#include<iostream> #include<cstring> using namespace std; class A { public: virtual void f() { cout<<"A"<<endl; }; }; class B:public A { public: void f() { cout<<"B"<<endl; } }; class C { void pp(){} }; int fun() { return 1; } int main() { A* a1=new B;//a1是A类型的指针指向一个B类型的对象(动态绑定) A* a2=new A;//a2是A类型的指针指向一个A类型的对象(动态绑定) B* b; C* c; b=dynamic_cast<B*>(a1);//fin,向下转换成功,a1之前指向的就是B类型的对象,所以可以转换成B类型的指针。 if(b==NULL) cout<<"null"<<endl; else cout<<"not null"<<endl; b=dynamic_cast<B*>(a2);//结果为null,向下转换失败 if(b==NULL) cout<<"null"<<endl; else cout<<"not null"<<endl; c=dynamic_cast<C*>(a2);//结果为null,向下转换失败 if(c==NULL) cout<<"null"<<endl; else cout<<"not null"<<endl;return 0; }
综合用例:
#include <bits/stdc++.h> using namespace std; class Base { public: Base() :b(1) {} virtual void fun() {}; int b; }; class Son : public Base { public: Son() :d(2) {} int d; }; int main() { int n = 97; //reinterpret_cast int *p = &n; //以下两者效果相同 char *c = reinterpret_cast<char*> (p); char *c2 = (char*)(p); cout << "reinterpret_cast输出:"<< *c2 << endl; //const_cast const int *p2 = &n; int *p3 = const_cast<int*>(p2); *p3 = 100; cout << "const_cast输出:" << *p3 << endl; Base* b1 = new Son; Base* b2 = new Base; //static_cast Son* s1 = static_cast<Son*>(b1); //同类型转换 Son* s2 = static_cast<Son*>(b2); //下行转换,不安全 cout << "static_cast输出:"<< endl; cout << s1->d << endl; cout << s2->d << endl; //下行转换,原先父对象没有d成员,输出垃圾值 //dynamic_cast Son* s3 = dynamic_cast<Son*>(b1); //同类型转换 Son* s4 = dynamic_cast<Son*>(b2); //下行转换,安全 cout << "dynamic_cast输出:" << endl; cout << s3->d << endl; if(s4 == nullptr) cout << "s4指针为nullptr" << endl; else cout << s4->d << endl; return 0; } //输出结果 //reinterpret_cast输出:a //const_cast输出:100 //static_cast输出: //2 //-33686019 //dynamic_cast输出: //2 //s4指针为nullptr
原文章:https://interviewguide.cn/notes/03-hunting_job/02-interview/01-01-04-basic.html
https://blog.csdn.net/q610098308/article/details/115915802