我试图弄清楚为什么有些代码库使用IsA()来确定对象多态性,如果在C ++中你已经可以安全地进行上传和下调(使用dynamic_cast)?
到目前为止,我认为唯一有用的案例是当你整合一个链接到c ++代码库的脚本环境时?
谢谢!
答案 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
。