我需要找到指针指向的对象类型。 代码如下。
//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链变得太长了。 我们可以使用开关或更简单的方法检查窗口类型吗?
编辑:我在记录器模块中工作。我想,记录器不应该为了记录目的而调用派生类虚函数。它应该自己做。所以我放弃了虚函数方法。
答案 0 :(得分:7)
首先对std::string
之类的字符串使用更高级别的构造
其次,如果您需要检查窗口的类型,那么您的设计是错误的
使用Liskov substitution principle进行正确设计
它基本上意味着任何派生的Window
对象都可以用它的超类来替换
只有当两者共享相同的接口且派生类不违反基类提供的合同时,才会发生这种情况
如果您需要某种机制来动态应用行为,请使用Visitor Pattern
答案 1 :(得分:1)
创建一个字典(set / hashmap),其中字符串为键,行为为值。
将行为用作值可以通过两种方式完成:
更新: 我发现这篇文章可能正是您所寻找的: http://www.dreamincode.net/forums/topic/38412-the-command-pattern-c/
答案 2 :(得分:1)
以下是按优先顺序排列的事项:
else if
子句。这是首选方案,因为您当前的策略是广泛认可的设计不良的症状,这是建议的补救措施。::std::map< ::std::string, void (*)(Window *pWindow)>
。这将允许您查找要在地图中调用的函数,这更快,更容易添加。这还需要您将每个else if
子句拆分为自己的函数。::std::map< ::std::string, int>
。这将允许您查找相应字符串的整数,然后您可以在整数上switch
。还有其他重构策略可供选择,这里更类似于选项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方式。
最后,如果您发现自己愿意在层次结构中添加许多不同的操作,我将建议使用一个众所周知的设计模式:访问者。有一种称为非循环访问者的变体,它有助于处理依赖关系。