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也就不能用传统的转换方式来实现了。


posted @ 2011-08-26 17:21  wtx  阅读(246)  评论(0)    收藏  举报