只有当你的类有一个虚拟表时,RTTI才能工作。如果你有一个虚拟表,你可以实现虚拟函数。您应该在对象类型的开关上使用虚函数的原因是,它与继承链一起工作得更好,并且在添加新类时不那么脆弱。
例如:
代码语言:javascript复制class A : public V {}
class B : public V{}
void do_something( const V & v )
{
if (typeid(A) == typeid(v)) { .. its an A .. }
if (typeid(B) == typeid(v)) { .. its a B .. }
}
int main()
{
do_something( A() );
do_something( B() );
}现在,如果我们添加一个也是从V派生的新类C并调用do_something( C() ) (而不更改do_something的实现),则不会发生任何事情。(编译时没有错误)。如果我们添加一个从A派生的类D,也不会出错,也不会发生任何事情。
将这与虚函数的行为进行对比
代码语言:javascript复制struct V
{
virtual void do_something() const =0;
};
struct A
{
virtual void do_something() const { ... its an A ... }
}
struct B
{
virtual void do_somethine() const { ... its a B ... }
}
void do_something( const V & v )
{
v.do_something();
}现在,如果我们从V派生C,并且没有实现C::do_something(),我们将得到一个编译时错误。如果我们从A派生D,并且不实现D::do_something(),我们将得到对A::do_something()的调用。
因此,这是虚拟函数比RTTI更受青睐的主要原因。但是,有时您可能会觉得do_something的行为不属于您的V或A B C类。因此,您可能会使用RTTI (通过typeid或dynamic_cast)。更好的解决方案通常是实现类层次结构的访问者模式。