C ++中IsA()的重点是什么?

时间:2010-11-08 21:12:12

标签: c++ polymorphism

我试图弄清楚为什么有些代码库使用IsA()来确定对象多态性,如果在C ++中你已经可以安全地进行上传和下调(使用dynamic_cast)?

到目前为止,我认为唯一有用的案例是当你整合一个链接到c ++代码库的脚本环境时?

谢谢!

5 个答案:

答案 0 :(得分:8)

C ++中需要IsA()函数,甚至dynamic_cast<>()的原因很少。这类代码的最糟糕的例子是使用dynamic_cast的巨型if-then语句,或type字段上的switch语句。这些代表了维护的噩梦,添加类可能涉及更新数十个或数百个不同的位置以支持新类。

例如:

为:

// Don't do this:
void PrintName(Base *b, ostream &o)
{
   if (dynamic_cast<DerivedA *>(b) != NULL)
      o << "Derived A";
   if (dynamic_cast<DerivedB *>(b) != NULL)
      o << "Derived B";
   if (dynamic_cast<DerivedC *>(b) != NULL)
      o << "Derived C";
}

更好:

void PrintName(Base *b, ostream &o)
{
   o << b->GetName();
}

这显然是在检查null,并使用智能指针等。同样,如果你要查询类型以在不同的行为之间进行选择,你需要问为什么你为每种类型做了不同的事情,并且将该行为决定移入对象。

为:

// Don't do this:
void ObjectBase::ApplyForceToObject(const Force &f)
{
    if (dynamic_cast<Wall*>(this) != NULL
        || dynamic_cast<Floor*>(b) != NULL)
    {
        // Do nothing
    }
    else
    {
        // Accelerate object
    }
}

更好:

void ObjectBase::ApplyForceToObject(const Force &f)
{
    if (IsFixedObject())
    {
        // Do nothing
    }
    else
    {
        // Accelerate object
    }
}
...
bool ObjectBase::IsFixedObject() { return false; }
bool Wall::IsFixedObject() { return true; }
bool Floor::IsFixedObject() { return true; }

答案 1 :(得分:5)

在现代C ++中没有任何意义。

1998年标准化之前的框架可以提供IsA功能。

E.g。我记得在MFC中有这样的功能。

另外,正如您所指出的,当处理用其他语言实现的对象(类型不是由C ++类型表示)时,它可能是有用的。

干杯&amp;第h。,

答案 2 :(得分:3)

因为dynamic-cast依赖于RTTI,这可能会影响性能。它也更方便可靠。

答案 3 :(得分:0)

如何在没有RTTI的情况下查找运行时类型信息的示例

MFC使用名为IsKindOf()的函数作为运行时类型信息。 MFC用于查找类型信息的方法有点像下面的示例。

#define RUNTIME_CLASS(class_name) (class_name::GetThisClass())
#define RUNTIME_OBJ(class_name) (class##class_name)
struct RunTimeClass
{
    string name;
};
class base
{
    static RunTimeClass RUNTIME_OBJ(base); //watch the naming 
public:

    bool IsExactKind(RunTimeClass* pRTclass)
    {
        if(pRTclass == GetRunTimeClass())
        {
            return true;
        }
        return false;

    }

    static RunTimeClass* GetThisClass()
    {
        return &RUNTIME_OBJ(base);      
    }

    virtual RunTimeClass* GetRunTimeClass()
    {
        return &RUNTIME_OBJ(base);
    }
    virtual ~base() = 0;
};

class derived: public base
{
    static RunTimeClass RUNTIME_OBJ(derived); //watch the naming
public:
    RunTimeClass* GetRunTimeClass()
    {
        return &RUNTIME_OBJ(derived);       
    }

    static RunTimeClass* GetThisClass()
    {
        return &RUNTIME_OBJ(derived);       
    }

};

class derived2: public derived
{
    static RunTimeClass RUNTIME_OBJ(derived2); //watch the naming
public:
    RunTimeClass* GetRunTimeClass()
    {
        return &RUNTIME_OBJ(derived2);      
    }

    static RunTimeClass* GetThisClass()
    {
        return &RUNTIME_OBJ(derived2);      
    }

};

在cpp文件中

RunTimeClass base::classbase = {"base"}; //not using the macro RUNTIME_OBJ
RunTimeClass derived::classderived = {"derived"}; //not using the macro RUNTIME_OBJ
RunTimeClass derived2::classderived2 = {"derived2"}; //not using the macro RUNTIME_OBJ
base::~base() {}
void main()
{
    derived *ptrDer = new derived();
    bool isder = ptrDer->IsExactKind(RUNTIME_CLASS(derived));

    derived2 *ptrDer2 = new derived2();
    isder = ptrDer2->IsExactKind(RUNTIME_CLASS(derived2));

    delete ptrDer;
    delete ptrDer2;
}

请注意,这只能找到对象是否属于确切的类类型。要添加类型信息,您只需从base继承并添加Runtimeclass变量并实现两个函数getthisclass(),getruntimeclass()。 MFC使用CObject作为基类,提供类似的功能。此外,还有更多的宏可以让您的生活更轻松。 MFC中的IsKindOF()函数遍历整个层次结构并找出对象“是一种”类(在我的缩小版本中不存在)。你可以看到这与RTTI有些类似,因此我猜没有性能差异。它存在于MFC中,因为它存在于RTTI之前。

因此,如果有一个比RTTI更好的IsA()函数,我希望看到实现。

答案 4 :(得分:0)

有时你没有RTTI(也许你正在使用内存/ CPU限制系统,禁用RTTI是强制解决方案)在这种情况下,你没有可用的dynamic_cast。如果你想使用类似于RTTI的东西,你通常会得到带有static_cast的IsA()解决方案。

IsA()函数的另一个可能用途是在编译时不知道所有类(可能是从共享库加载),或者您不想明确列出所有类型。这可以让你写出像

这样的东西
handleInstance( Instance * i )
{
  //libs has been filled through loading dynamic libraries.
  for( auto it = libs.begin() ; it!=libs.end() ; ++it )
  {
     if( i->IsA( it->type_key ) )
     {
        it->process( i );
     }
  }
}

虽然在这种情况下我可能会像

那样将测试条件内部转换出来
if( it->can_process( i ) )

can_process可以免费使用dynamic_cast