1.类型准换
c++是强类型语言。很多的转换(特别是对转换值产生不同的解释的转换)都需要显示进行,c++称之为类型转换。一般的类型转换存在两种转换语法:函数式和C风格式。
double x = 10.3;
int y;
y = int (x); // 函数式
y = (int) x; // C风格式
这两种风格的转换对于基础数据类型的转换是够用了,但是对于类与类,类与指针之间的转换却未加区别,这就会导致代码编译通过,但是可能发生运行时错误。见下面的例子:
#include <iostream>
using namespace std;
class Dummy {
double i,j;
};
class Addition {
int x,y;
public:
Addition (int a, int b) { x=a; y=b; }
int result() { return x+y;}
};
int main () {
Dummy d;
Addition * padd;
padd = (Addition*) &d;
cout << padd->result();
return 0;
}
在上述代码中声明了一个指向Addition的指针padd,但是却使用显示的类型转换给它赋值了一个与它所指类型不相干的对象的地址。
padd = (Addition*) &d;
不加限制的显示类型转换允许将任何一个指针转换成另外一个指向不同类型的指针,这种转换完全独立于指针所指对象的类型。随后调用result函数,将会导致一个运行时错误或者其他不可预知的错误。
为了控制类之间类似的转换,c++提供了四种转换控制符:
dynamic_cast <new_type> (expression)
reinterpret_cast <new_type> (expression)
static_cast <new_type> (expression)
const_cast <new_type> (expression)
这四种转换类似于传统的转换:
(new_type) expression
new_type (expression)
但是每一种转换都有其特性。
2.dynamic_cast
该运算符把expression转换成new_type的对象。new_type必须是类指针,类的引用或者void×。它的目的是确保转换的结果指向一个有效的完整的目的指针所指向的类型。dynamic_cast不仅支持pointer upcast (converting from pointer-to-derived to pointer-to-base),同时也支持downcast (convert from pointer-to-base to pointer-to-derived)。dynamic_cast可以在执行期决定真正的类型。如果downcast是安全的(也就说,如果基类指针或者引用确实指向一个派生类对象)这个运算符会传回适当转型过的指针。如果downcast不安全,这个运算符会传回空指针(也就是说,基类指针或者引用没有指向一个派生类对象)。
// dynamic_cast
#include <iostream>
#include <exception>
using namespace std;
class Base { virtual void dummy() {} };
class Derived: public Base { int a; };
int main () {
try {
Base * pba = new Derived;
Base * pbb = new Base;
Derived * pd;
pd = dynamic_cast<Derived*>(pba);
if (pd==0) cout << "Null pointer on first type-cast.\n";
pd = dynamic_cast<Derived*>(pbb);
if (pd==0) cout << "Null pointer on second type-cast.\n";
} catch (exception& e) {cout << "Exception: " << e.what();}
return 0;
}
上面的代码将会输出:
Null pointer on second type-cast.
dynamic_cast的转换是和编译器相关的。比如,vc6.0的在使用dynamic_cast的时候需要打开RITI编译选项。同时在转换的时候,vc6.0需要转换的指针所指向的类必须是多态类。但是g++的做法却不一样。在进行downcast转换的时候,转换的指针所指向的类必须是多态类(比如含有虚函数),但是如果进行pointer upcast转换的时候,没有这个限制。
3.static_caststatic_cast
可以在指向有联系的类的指针之间进行准换。同时支持upcasts和downcasts。但是不执行运行期间类型安全检查,不保证转换结果的完整性。
class Base {};
class Derived: public Base {};
Base * a = new Base;
Derived * b = static_cast<Derived*>(a);
以上代码是合法的,但是在运行期间会发生错误。
static_cast还能进行如下转换:
- 将void*转换成任意的指针类型;
- 把整数,浮点数,枚举转换成枚举类型;
- 显示的调用copy constructor或者operator操作符
- 把一个右值准换成引用
关于“显示的调用copy constructor或者operator操作符”例子如下:
#include <iostream>
#include <exception>
using namespace std;
class A{
public:
A() {
cout<<"A constructor"<<endl;
}
A(A&){
cout<<"A copy constructor"<<endl;
}
A& operator=(A& a){
cout<<"A copy assign"<<endl;
return *this;
}
};
int main () {
A a1;
A a2;
a2 = static_cast<A>(a1);
return 0;
}
a2 = static_cast<A>(a1)首先会根据a1调用A的copy constructor构造一个临时的对象,然后调用a2的copy assign操作符给a2赋值。
所以运行结果为:
A constructor
A constructor
A copy constructor
A copy assign
3.reinterpret_cast
reinterpret_cast把一个指针转换成另外一个指针,即使这两个指针所指向的对象没有任何的联系。4.const_cast
该运算符用来修改类型的const或volatile属性。5.typeid
typeid的表达式如下:typeid(e)
这里e是任意表达式或者类型名。如果表达式的类型是类类型且该类含有一个或者多个虚函数,则表达式的动态类型可能不同于它的静态编译时的类型。typeid的结果是返回名为type_info的标准库类型的对象引用。
6.参考资料
《c++ primer》《百度百科》
http://www.cplusplus.com/doc/tutorial/typecasting/