运行时类型比较

时间:2010-08-19 08:08:50

标签: c++ rtti

我需要找到指针指向的对象类型。 代码如下。

//pWindow is pointer to either base Window object or derived Window objects like //Window_Derived.
const char* windowName = typeid(*pWindow).name(); 
if(strcmp(windowName, typeid(Window).name()) == 0)
{
  // ...
}
else if(strcmp(windowName, typeid(Window_Derived).name()) == 0)
{
  // ...     
}

由于我不能使用switch语句来比较字符串,我被迫使用if else链。 但是随着我拥有的窗口类型的数量很多,这个if else链变得太长了。 我们可以使用开关或更简单的方法检查窗口类型吗?

编辑:我在记录器模块中工作。我想,记录器不应该为了记录目的而调用派生类虚函数。它应该自己做。所以我放弃了虚函数方法。

5 个答案:

答案 0 :(得分:7)

首先对std::string之类的字符串使用更高级别的构造 其次,如果您需要检查窗口的类型,那么您的设计是错误的 使用Liskov substitution principle进行正确设计 它基本上意味着任何派生的Window对象都可以用它的超类来替换 只有当两者共享相同的接口且派生类不违反基类提供的合同时,才会发生这种情况 如果您需要某种机制来动态应用行为,请使用Visitor Pattern

答案 1 :(得分:1)

创建一个字典(set / hashmap),其中字符串为键,行为为值。

将行为用作值可以通过两种方式完成:

  1. 将每个行为封装在其中 自己继承自的类 接口采用“DoAction”方法 执行行为
  2. 使用函数指针
  3. 更新: 我发现这篇文章可能正是您所寻找的: http://www.dreamincode.net/forums/topic/38412-the-command-pattern-c/

答案 2 :(得分:1)

以下是按优先顺序排列的事项:

  1. 向基类添加一个新的虚方法,然后简单地调用它。然后在每个派生类中放入一个同名的虚方法,在其中实现相应的else if子句。这是首选方案,因为您当前的策略是广泛认可的设计不良的症状,这是建议的补救措施。
  2. 使用::std::map< ::std::string, void (*)(Window *pWindow)>。这将允许您查找要在地图中调用的函数,这更快,更容易添加。这还需要您将每个else if子句拆分为自己的函数。
  3. 使用::std::map< ::std::string, int>。这将允许您查找相应字符串的整数,然后您可以在整数上switch
  4. 还有其他重构策略可供选择,这里更类似于选项1。例如,如果无法向Window类添加方法,则可以创建具有所需方法的接口类。然后你可以创建一个函数,使用dynamic_cast来确定对象是否实现了接口类并在这种情况下调用方法,然后使用else if构造处理剩下的几个案例。

答案 3 :(得分:0)

您可以尝试将所有typeid(...)。name()值放在地图中,然后在地图中执行find()。您可以映射到可以在switch语句或函数指针中使用的int。更好的是,你可能会再次看到在你需要的每种类型中获得一个虚函数。

答案 4 :(得分:0)

你要求的是可能的,它也不太可能成为解决问题的好方法。

有效地,if / else if / else链是丑陋的,因此首先想到的解决方案是使用一个可以解除此问题的构造,一个关联容器会浮现在脑海中,而默认的容器显然是std::unordered_map

考虑到这个容器的类型,您将意识到需要使用typename作为键并将其与仿函数对象相关联...

然而,有更多优雅的结构。首先,当然是使用virtual方法。

class Base
{
public:
  void execute() const { this->executeImpl(); }
private:
  virtual void executeImpl() const { /* default impl */ }
};

class Derived: public Base
{
  virtual void executeImpl() const { /* another impl */ }
};

这是处理这类要求的OO方式。

最后,如果您发现自己愿意在层次结构中添加许多不同的操作,我将建议使用一个众所周知的设计模式:访问者。有一种称为非循环访问者的变体,它有助于处理依赖关系。