dynamic_cast 是c++ 提供的支持RTTI的操作符之一。其操作数必须有一个或者多个的虚函数(以提供vtable,供RTTI进行类型识别)来劲省运行时的类型识别,否则dynamic_cast只能用来做安全的转换,例如从派生类指针转换成基类指针.
下面是其一个用途:
class A ... {
public:
virtual void a()
...{
cout<<"aA"<<endl;
return;
};
} ;
class C ... {
public:
virtual void c()
...{
cout<<"cC"<<endl;
return;
}
} ;
class B: public A, public C ... {
public:
virtual void a()
...{
cout<<"aB"<<endl;
return;
}
virtual void c()
...{
cout<<"cB"<<endl;
return;
}
} ;
B b;
A * aa = & b;
aa -> a(); // 输出是 aB
// B *bb = aa; // 不能直接转换,error
B * bb = static_cast < B *> (aa); // 同样OK,但是不能提供判断
bb -> a(); // 输出同样是 aB,编译使确定的
C * cc = & b;
cc -> c(); // 输出是cB
// cc->a(); // error
// A *ca = static_cast<A*>(cc); // 不能运行时识别
A * ca = dynamic_cast < A *> (cc);
aa -> a();
如上所见:一般的编译时类型转换一般只能提供 基类向派生类转换(指针),在派生类向基类转换时发生切割现像。其实当没有虚函数的是 dynamic—cast 的作用体现不出来。
dynamic_cast的使用必须注意:
1. 使用虚函数以支持RTTI。(以说明)
2.转换失败的时候的处理。
dynamic_cast 的参数(就是需要转换的部分)必须是一个指针或者引用,因为只有通过这两钟形式才能获得运行时的类别。
采用指针时:如果转换失败的话会dynamic_cast会返回0,所以使用的时候必须加以检查。例如在上述定义的情况下追加定义:
class
D:
public
A
...
{}
;
然后
D
*
d
=
new
D;
if (B * db = dynamic_cast < B *> (d)) ... {
cout<<"OK"<<endl;
}
else ... {
cout<<"error"<<endl;
}
if (B * db = dynamic_cast < B *> (d)) ... {
cout<<"OK"<<endl;
}
else ... {
cout<<"error"<<endl;
}
此时输出是 error!!
对于使用引用的 dynamic_cast,由于不可能给一个引用赋值为空,所以我们不能通过简单的= 0 来判断,此时dynamic_cast 转换失败时会抛出异常。
try
...
{
D dd;
D &d = dd;
B &bb = dynamic_cast<B&>(d);
}
catch (bad_cast) ... {
cout<<"catch the error"<<endl;
}
D dd;
D &d = dd;
B &bb = dynamic_cast<B&>(d);
}
catch (bad_cast) ... {
cout<<"catch the error"<<endl;
}