前言
C++的四种强制类型转换,所以C++不是类型安全的.
关键字分别是:static_cast,dynamic_cast,const_cast,reinterpret_cast
新类型的强制转换可以提供更好的控制强制转换过程,孕育控制各种不同类的强制转换,C++风格是static_cast(content).C++风格的强制转换其它的好处是,它们能清晰的表明它们要干什么,程序员只要扫一眼这样的代码,就立即知道这个强制转换的目的.
四种转换的区别
static_cast
可以实现C++中内置基本数据类型之间的相互转换.
int c=static_cast<int>(7.98);
如果涉及到类的话,static_cast只能在有相互联系的类型中进行相互转换,不一定包含虚函数
#include<iostream>
using namespace std;
class A
{};
class B:public A
{};
class C
{};
int main()
{
B b;
A& a1=b;
//向上转型,及把子类类型转换为父类类型.
B& another_b=static_cast<B&>(a1);
}
const_cast
const_cast操作不能在不同的种类之间转换,它仅仅把一个它作用的表达式转换成常量,它可以使一个本来不是const类型的数据转换成const类型,或者把const属性去掉.
#include<iostream>
struct type{
type():i(3){}
void m1(int v) const{
//this->i = v;
/**因为函数是const的,所以type::i是可读的,但是const_cast去掉了调用此函数对象的const属性.
*
*/
const_cast<type*>(this)->i = v;
}
int i;
};
int main(int argc,char *argv[])
{
int i = 3;
const int& cref_i = i;
const_cast<int&>(cref_i) = 4; //去掉了cref_i的const属性.
//cref_i=4; 错误,引用cref_i是只读的
std::cout << "i = "<<i<<std::endl;
type t;
t.m1(4);
std::cout << "type::i = "<<t.i << std::endl;
const int j = 3;
int *pj = const_cast<int *>(&j);
*pj = 4;
return 0;
}
reinterpret_cast
有着和C风格的强制转换同样的能力,它可以转换任何内置的数据类型为其它任何的数据类型,也可以转换任何指针类型为其它的类型,它甚至可以转换内置类型为指针,无须考虑类型安全或者常量的情况,不到万不得已绝不使用.
#include<iostream>
#include<cassert>
#include<cstdlib>
int f(){return 42;}
int main(int argc,char *argv[])
{
int i = 7;
//pointer to integer and back
uintptr_t v1 = reinterpret_cast<uintptr_t>(&i);
std::cout << "The value of &i is 0x"<<std::hex<< v1 <<std::endl;
int *p1 = reinterpret_cast<int*>(v1);
std::cout <<"*p1: "<< *p1 <<std::endl;
assert(p1 == &i);
//pointer to function to another and back.
void(*fp1)() = reinterpret_cast<void(*)()>(f);
//fp1(); undefined behavior
int(*fp2)() = reinterpret_cast<int(*)()>(fp1);
std::cout << std::dec <<fp2()<<std::endl;
//type aliasing through pointer
char* p2 = reinterpret_cast<char *>(&i);
if(p2[0] == '\x7'){
std::cout << "This system is little-endian"<<std::endl;
}else{
std::cout << "This system is big-endian"<<std::endl;
}
//type aliasing through reference
reinterpret_cast<unsigned int&>(i) = 42;
std::cout << i<< std::endl;
return 0;
}
dynamic_cast:
(1) 其它三种都是编译时完成的,dynamic_cast是运行时处理的,运行要进程类型检查.
(2)不能用于内置的基本数据类型的强制转换.
(3)dynamic_cast转换如果成功的话返回的是指向类的指针或引用,转换失败的话则返回NULL.
(4)使用dynamic_cast进行转换的,基类中一定要有虚函数,否则编译不通过.
B中需要检测有虚函数的原因:类中存在虚函数,就说明它有想要让基类指针或引用指向派生类对象的情况,此时转换才有意义.
这是由于运行时类型检查需要运行时类型信息,而这个信息存储在类的虚函数表中(关于虚函数表的概念)中.
只有定义了虚函数的类才有虚函数表.
(5)在类的转换时,在类层次之间进行上行转换时,dynamic_cast和static_cast的效果是一样的,在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全,向上转换即为指向子类对象的向下转换,即将父类指针转换为子类指针,向下转换的成功与否还与将要转换的类型有关,即要转换的指针指向的对象的实际类型与转换以后的对象类型一定要相同,否则转换失败.
#include<iostream>
class Base
{
public:
int b;
virtual void Test(){
std::cout << "base"<<std::endl;
}
};
class Derived:public Base{
public:
int d;
virtual void Test(){
std::cout <<"Derived"<<std::endl;
}
};
int main(int argc,char *argv[])
{
//切割:覆盖方法和子类数据丢失的现象生成切割(slice)
Derived d;
Base b = d; //直接赋值(产生切割)
b.Test();
std::cout <<"dd"<<std::endl;
Base& b2 = d; //使用引用赋值(不产生切割)
b2.Test();
Base* b3 = &d; //使用指针赋值(不产生切割)
b3->Test();
//使用dynamic_cast 进行向下强制类型转换.
Base *b1 = new Derived;
Derived *d1 = dynamic_cast<Derived *>(b1);
if(!d1){
std::cout << "dynamic_cast err!"<<std::endl;
}else{
d1->Test();
}
return 1;
}