C ++复习之类型转换(学习)
来自于:http://www.cnblogs.com/ider/archive/2011/08/05/cpp_cast_operator_part6.html
C++中提供了4中转换运算符
const_cast,static_cast,dynamic_cast,reinterpret_cast
其中const_cast转换符是用来移除变量的const或volatile限定符
const_cast 实现的原因是C+对于指针的转换是任意的,它不会进行类型检查,任何指针间的转换是互相进行的
#include <iostream>
using namespace std;
int main()
{
const int i = 10;
// Error: invalid conversion from 'const int*' to 'int*'
// int *modifier = &i;
//invalid initialization of reference of type 'int&'
//int & modifier = i;
const int *const_p = &i;
int *modifier = const_cast<int *>(const_p);
cout << i << " " << *modifier << endl;
/*
IBM的C++指南称呼“*modifier = 7;”为
“未定义行为(Undefined Behavior)”。
所谓未定义,是说这个语句在标准C++中没有明确的规定,
由编译器来决定如何处理。
*/
*modifier = 2;//modifer 的改变对于i没有影响,i是const,不管是否使用了const_cast
cout << i << " " << *modifier << endl;
//他们3个指向相同的地址
cout << "i: "<< &i <<endl;
cout << "const_p: "<< const_p <<endl;
cout << "modifier: "<< modifier <<endl;
return 0;
}
C++中使用const_cast的原因是,当定义一个变量类型为const,但是调用的函数接受形参为非const类型的变量时,进行const_cast操作
#include <iostream>
#include <string>
using namespace std;
void printer(int *v,string s = "\n")
{
cout << *v << s;
}
int main()
{
const int i = 20;
printer(const_cast<int *>(&i));
return 0;
}
IBM指南中还有另一种需要去除const的情况,我们定义的是非const变量,但却使用了一个const的指针指向了这个非const的变量,在某一处时,我们想要修改这个变量的值
#include <iostream>
#include <string>
using namespace std;
int main()
{
int i = 20;
int * const const_p = &i; //这里应该是 const型的指针,指针的地址不变,而不是指向的内容不变
int *modifier = const_cast<int *>(const_p);
*modifier = 7;
cout << "i:" << i << endl;
return 0;
}
2. static_cast 不像const_cast去除变量的const,static_cast,static_cast并不是用来去除变量的static引用的,static_cast可以应用于指针和引用上,还可以应用于基础数据和对象上,reinterpret_cast用于"没有关系"的类型上,而static_cast必须用于两者具有一定的关系
reinterpret_cast用于任意指针之间进行互相转换,编译器不会报错
#include <iostream>
using namespace std;
unsigned short hash(void *p)
{
unsigned long val = reinterpret_cast<unsigned long>(p);
return (unsigned short) (val ^ (val >> 16));
}
class A{};
class B{};
int main()
{
typedef unsigned short (* FuncPointer)(void *);
FuncPointer fp = hash;
int a[10];
const int *ch = a;
char chArray[4] = {'a','b','c','d'};
fp = reinterpret_cast<FuncPointer>(ch);
ch = reinterpret_cast<int *>(chArray);
cout << hex << *ch << endl;
cout << "------------------" << endl;
A * a1 = new A();
B *b = reinterpret_cast<B *> (a1);//将a1指针转为为b指针
return 0;
}
但是static_cast就不能完成这个工作,目标指针域原指针必须要有一定的关系
对于static_cast所需的关系,继承 算是一个,但是一般不使用static_cast,而是使用dynamic_cast,但是static_cast也支持,但是从基类到子类的转换,static_cast并不是安全的
#include <iostream>
using namespace std;
class A{};
class B:public A{};
int main()
{
B * b = new B();
A *a = static_cast<A *>(b);
A *a1 = new A();
B *b1 = static_cast<B *>(a1);
return 0;
}
static_cast真正的用途在于基础类型和对象的转换上,而且基于基础类和对象的转换是其他3个cast所不能达到的
float floatValue = 21.7;
int intValue = 7;
cout << floatValue / 7 << "\t\t" << static_cast<int> (floatValue)/7 <<endl;
cout << intValue/3 << "\t\t" << static_cast<double> (intValue)/3 << endl;
而对于对象的转换,也是需要有关系的,这层关系是:
构造函数和类型转换运算符
static_cast会根据上述顺序找到合适的方法进行类型转换,但是赋值运算符不算在内,赋值运算符本身也是一种运算符,不能再当转换运算符来操作
3. dynamic_cast,与static_cast一样,也是需要有一定的关系的,而且dynamic_cast还涉及到编译器的属性,面向对象的多态性,程序运行时的状态等
dynamic_cast实际上只接受基于类对象的指针和引用的类转换
#include <iostream>
using namespace std;
class A
{
public:
A(string n = "A"){name = n;}
virtual ~A(){}
virtual void speak(){
cout << " A: " << name << endl;
}
protected:
string name;
};
class B:public A
{
public:
B(string n = "B"):A(n){}
virtual ~B(){}
virtual void specak(){
cout << "B:" << name << endl;
}
//name 继承自A的protected name
};
class C
{
public:
C(string n = "C"){name = n;}
virtual ~C(){}
void speak()
{
cout << "C: " << endl;
}
private:
string name;
};
int main()
{
cout << "-------------------------" << endl;
B *b1 = new B("b1");
A *a1 = dynamic_cast<A *>(b1); //多态,dynamic_cast和static_cast从子类到基类的转化都是正确的
a1->speak();
cout << "-------------------------" << endl;
B *b2 = new B("b2");
A *a2 = static_cast<A *>(b2);
a2->speak();
cout << "-------------------------" << endl;
//而对于从基类到子类的转化,dynamic_cast和static_cast也都是成功的,但是正确性上,dynamic_cast显示的是空指针,stati//c_cast则显示的是非空指针,static_cast是错误的
A *a3 = new A("a3");
B *b3 = dynamic_cast<B *>(a3);
if(b3)
{
b3->speak();
}
else
{
cout << "null" << endl;
}
cout << "-------------------------" << endl;
A * a4 = new A("a4");
B * b4 = static_cast<B *>(a4);
if(b4)
{
b4->speak();
}
else
{
cout << "null" << endl;
}
cout << "-------------------------" << endl;
// 而对于没有关系的两个类,dynamic_cast依然返回的是空指针以表示转化是不成立的,static_cast直接在编译器就拒绝了这种转换,interpret_cast成功的进行了转换,但是返回值不是空指针,显然是错误的
C *c1 = dynamic_cast<C *>(b1);
if(c1)
{
c1->speak();
}
else
{
cout << "null" << endl;
}
cout << "-------------------------" << endl;
C *c = reinterpret_cast<C *>(b2);
if(c)
{
c->speak();
}
else
{
cout << "null" << endl;
}
cout << "-------------------------" << endl;
//程序里还用dynamic_cast希望把用其他转换运算符转换过去的指针转换回来。对于使用static_cast转换后指向了子类对象的基类指针,dynamic_cast判定转换是合理有效的,因此转换成功获得一个非空的指针并且正确输出了结果;而对于reinterpret_cast转换的类型,的确如它的功能一样——重新解析,变成新的类型,所以才得到dynamic_cast判定该类型已经不是原来的类型结果,转换得到了一个空指针。
B *b5 = dynamic_cast<B *>(b4);
if(b5)
{
b5->speak();
}
else
{
cout << "null" << endl;
}
cout << "-------------------------" << endl;
B *b6 = dynamic_cast<B *>(c);
if(b6)
{
b6->speak();
}
else
{
cout << "null" << endl;
}
cout << "-------------------------" << endl;
delete b1;
delete b2;
delete a3;
delete a4;
return 0;
}
运行结果如下

结论:
static_cast和reinterpret_cast运算符要么直接被编译器拒绝进行转换,要么就一定会得到相应的目标类型的值。 而dynamic_cast却会进行判别,确定源指针所指的内容,是否真的合适被目标指针接受。如果是否定的,那么dynamic_cast则会返回null。这是通过检查"运行期类型信息"(Runtime type information,RTTI)来判定的,它还受到编译器的影响,有些编译器需要设置开启才能让程序正确运行,因此dynamic_cast也就不能用传统的转换方式来实现了。

浙公网安备 33010602011771号