一、C++的4中类型转换
我们应该比较熟悉C的类型转换即由圆括号和标识符组成,但是对于C的类型转换有时候到不到我们的要求,比如去除const 的类型转换,把一个指向基类的指针转化成指向子类的指针等等。下面就介绍C++引进的四个新的类型转换操作符,这四个操作符是:static_cast, const_cast, dynamic_cast, 和reinterpret_cast。
1,const_cast 除去对象的常属性。转换的是表达式而非自身. 形式:const_cast< type > ( object )
2,static_cast 用来进行非多态的任何转换。拒绝了运行时的类型检查。形式:static_cast< type > ( object )
3,dynamic_cast 这是唯一的运行时转换符。可完成类族中的向下类型转换——将父类的指针变为子类的指针。形式:dynamic_cast< type > (object)
4,reinterpret_cast 将一种数据从根本上变为另一种完全不兼容的类型。形式:reinterpret_cast< type > ( object )
下面分别仔细介绍:
const_cast< type > ( object )
该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外, type_id和expression的类型是一样的。
A、常量指针被转化成非常量的指针,并且仍然指向原来的对象;
B、常量引用被转换成非常量的引用,并且仍然指向原来的对象;
下面是一些例子:
class Test
{
public:
Test(int m_=0):m(m_){}
public:
int m;
};
int main()
{
const Test t1;
//b1.m = 1; //compile error
// 体现出转换为指针类型
Test *t2 = const_cast<Test*>(&t1);
//左侧为引用类型
Test &t3 = const_cast<Test&>(t1);
//对t2或t3的数据成员做改变,就是对t1的值在做改变
t2->m = 2; //ok
printf("%d\n", t1.m);
t3.m = 3; //ok
printf("%d\n", t1.m);
return 0;
}
使用const_cast可以返回一个指向非常量的指针(或引用)指向原const 常量对象,可以通过转换后的指针(或引用)对它的成员进行改变。
可见只有使用const_cast才能将 const性质转换掉。在这种情况下,试图使用其他三种形式的强制转换都会导致编译时的错误。除此之外,
用 const_cast 符来执行其他任何类型转换,都会引起编译错误。
static_cast< type > ( object )
该运算符把expression转换为type-id类型,但没有运行时类型检查来保证转换的安全性。它主要有如下几种用法:
①用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。进行上行转换(把派生类的指针或引用转换成基类表示)是安全的;
进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的。
②用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。
③把空指针转换成目标类型的空指针。
④把任何类型的表达式转换成void类型。
注意:static_cast不能转换掉expression的const、volatile、或者__unaligned属性。
编译器隐式执行的任何类型转换都可以由static_cast显式完成。如:
float pi=3.1415;
int a=static_cast<int>(pi);
dynamic_cast< type > (object)
该运算符把object转换成type类型的对象。type必须是类的指针、类的引用或者void*;
dynamic_cast运算符可以在执行期决定真正的类型。如果downcast是安全的(基类指针或者引用指向一个派生类对象,把基类指针或引用转换为派生类指针或引用)
这个运算符会传回适当转型过的指针。如果downcast不安全(基类指针或者引用没有指向一个派生类对象),这个运算符会传回空指针。
dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。
在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的;
在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。
例子:
class Base
{
public:
virtual void print()
{
printf("I am Base. virtual print.\n");
}
};
class Der:public Base
{
public:
void print()
{
printf("I am Derive. virtual print.\n");
}
void print_non_vir()
{
printf("I am Derive. non virtual print.\n");
}
};
int main()
{
Base b;
Der d;
Base *pbb=&b;
Base *pbd=&d;
pbd->print();
// pbd->print_non_vir(); //error
dynamic_cast<Der*>(pbd)->print_non_vir();
// dynamic_cast<Der*>(pbb)->n=2;//error pbb所指对象为Base
static_cast<Der*>(pbd)->print_non_vir();
return 0;
}
注意:Base要有虚函数,否则会编译出错;static_cast则没有这个限制。