const_cast
- const_cast的主要用途是去掉对象引用或指针的const属性。但是即使转换后,对原始的const对象也不能真正的改变其值,只能是改变其引用或者*指针的值(具体如何实现没有深入研究,参考下面的代码)。
- const_cast的使用场景不在于要修改const对象的值,而是主要用在参数传递等场景。参考代码中的注释。
#include <iostream>
using namespace std;
void test_const_cast(void) {
const int a = 10;
const int * p = &a;
int * p1 = const_cast<int *>(p);
*p1 = 20;
cout << a << " " << *p << " " << *p1 << endl;
cout << &a << " " << p << " " << p1 << endl;
const int & ref = a;
int & ref1 = const_cast<int &>(ref);
ref1 = 30;
cout << a << " " << ref << " " << ref1 << endl;
int b = 7;
const int * bp = &b;
int * bp1 = const_cast<int *>(bp);
*bp1 = 14;
cout << b << " " << *bp << " " << *bp1 << endl;
}
int main(int argc, char ** argv) {
test_const_cast();
return 0;
}
static_cast
- static_cast和dynamic_cast的验证都记载在如下的代码中,代码的注释为验证的结论。在最后会有一个static_cast和dynamic_cast的不同的说明。
#include <iostream>
using namespace std;
class A {
};
class B {
};
class A1 : public A {
};
class A2 : public A {
};
class C {
public:
C():a(10) {}
virtual ~C(){}
void getType( void ) { cout << "The class is C" << endl; }
void testC( void ) { cout << "C" << endl; }
void intC( void ) { cout << a << endl; }
private:
int a;
};
class C1 : public C {
};
class D {
public:
virtual ~D(){}
void getType( void ) { cout << "The class is D" << endl; }
void testD( void ) { cout << "D" << endl; }
};
void test(void) {
char a = 'a';
int vInt = static_cast<int>(a);
cout << a << " " << vInt << endl;
char b = 'b';
char * pChar = &b;
void * pVoid = &b;
char * pChar1 = static_cast<char *>(pVoid);
void * pVoid1 = static_cast<void *>(pChar1);
cout << b << " " << *(char *)pVoid << " " << *pChar1 << " " << *(char *)pVoid1<< endl;
A * pA = new A();
B * pB = new B();
A1 * pA1 = new A1();
A * pAChange = static_cast<A *>(pA1);
A1 * pA1Change = static_cast<A1 *>(pA);
C * pC = new C();
D * pD = new D();
C * pCChange1 = static_cast<C *>(pD);
C * pCChange = dynamic_cast<C *>(pD);
pD->getType();
pCChange->getType();
pCChange->testC();
pCChange->intC();
}
int main(int argc, char ** argv) {
test();
return 0;
}
dynamic_cast
- 除了dynamic_cast以外的转换,其余的3种类型转换操作符的行为的都是在编译期就得以确定的,转换是否成功,并不依赖被转换的对象。而dynamic_cast则不然.
- 首先,dynamic_cast依赖于RTTI信息.
- 其次,在转换时,dynamic_cast会检查转换的source对象是否真的可以转换成target类型,这种检查不是语法上的,而是真实情况的检查。先看RTTI相关部分,通常,许多编译器都是通过vtable找到对象的RTTI信息的,这也就意味着,如果基类没有虚方法,也就无法判断一个基类指针变量所指对象的真实类型, 这时候,dynamic_cast只能用来做安全的转换,例如从派生类指针转换成基类指针.而这种转换其实并不需要dynamic_cast参与.也就是说,dynamic_cast是根据RTTI记载的信息来判断类型转换是否合法的.
- 从上面的static_cast的代码验证中可以看出来,static_cast在无关类之间的转换会报错;而dynamic_cast在无关类之间的转换不会报错。dynamic_cast的转换需要转换类好被转换类都有虚函数表。如果没有虚函数表,那么只能执行安全转换了,即从派生类转换成基类。
- 虽然dynamic_cast能在无关类之间进行转换,但是需要注意转换后的类型安全性需要程序员自己来验证,比如说调用转换前后的类共有的函数,那么能够调用到,但是如果两个类对这个函数的实现不同,比如转换前的类的实现中调用了私有成员变量b,但是转换后的类中的这个函数调用了私有成员变量a,因为转换前的类中没有成员变量a,那么转换后调用成员变量a肯定会出错,导致程序崩溃,具体参考实验代码。
static_cast和dynamic_cast的区别是什么
- 答案是:
- static_cast可以在基本类型之间做转换(即支持原来所有的隐式类型转换),不允许在基本类型指针之间做转换,不允许在无关类之间做转换,可以在void 和基本类型指针间做转换;dynamic_cast也不允许在无关类之间做转换,如果在无关类之间做转换那么转换后指针为NULL,dynamic也不允许在基本类型及基本类型指针或引用还有void 之间转换。
- dynamic_cast的被转换类必须有虚函数表。
- dynamic_cast被转换的指针的运行时类型必须与转换的目的类型相同,否则转换失败。
- static_cast和dynamic_cast都可以用在基类和派生类之间的转换,在派生类转换成基类的时候两者是相同的;在基类转换成派生的时候,static_cast的类型一致性要程序员自己保证,即程序员要自己保证转换前基类指针指向的类型与转换之后的派生类类型一致;而dynamic_cast的类型一致性可以指针自己来保证,即如果转换前后的运行时类型不一致,那么转换失败,转换后指针为NULL(所以如果使用dynamic_cast从基类指针转换到派生类指针,要想成功,那么转换的时候基类指针的运行时类型必须与要转换的派生类类型一致,否则转换失败,返回null).
- 这些强制转换一般用在参数传递过程中。
reinterpret_cast
- reinterpret_cast是对指针指向的内存位置的bit位做重新解释,可以转换任何类型的。
总结:
- C++的四种类型转换中,const_cast和reinterpret_cast的功能比较明确。容易混淆的就是static_cast和dynamic_cast的使用。通过上文的学习与总结,弄懂了两者的不同与使用场景。