我不确定如何制定我的问题,但这是我想要解决的难题:
if (config.a)
myObject = new Object<DummyInterface>();
else
myObject = new Object<RealInterface>();
所以任务是创建一个带有虚拟接口的对象(如果在config中指定它),否则使用真实接口类。 那我怎么声明myObject呢? 有几个选项,我可以让Object类派生自没有模板的抽象类:即:
class Base
{
...
}
template <class T>
class Object : public Base
{
...
}
然后我可以将myObject声明为:
Base* myObject;
但问题是:如果我的Object类声明了一个非虚方法怎么办:
template <class T>
class Object : public Base
{
public:
T getInterface() { return myInterface;}
private:
T myInterface;
}
我不能这样称呼它:
myObject->getInterface()
我无法进行动态转换,因为直到运行时才知道类型...
有任何建议如何绕过它?也许有另一种解决方案?
答案 0 :(得分:2)
一种方法是使用访客模式。这样,您的基类可以实现visit()
方法,您的派生实例可以覆盖...
例如......
SomeComponent
{
template <typename T> // I'm being lazy here, but you should handle specific types
void handle(T& cInst)
{
// do something
}
};
class Base
{
public:
virtual void visit(SomeComponent& cComp) = 0;
};
template <class T>
class Object : public Base
{
public:
virtual void visit(SomeComponent& cComp)
{
cComp.handle(*this);
}
};
现在你可以这样做
SomeComponent c;
Base* obj = new Object<int>;
obj->visit(c);
c
将获得正确的类型。
答案 1 :(得分:0)
if (config.a)
myObject = new Object<DummyInterface>();
else
myObject = new Object<RealInterface>();
这种结构在多态性方面是不正确的。 两个模板实例化是两个不同的类。最好的情况是你有类似的东西:
template <class T> SomeClass: public SomeBaseClass
{
};
.........
SomeBaseClass* myObject;
但它不会给你带来任何利润。 最简单和正确的解决方案是虚拟功能。访客模式似乎也很有用。
答案 2 :(得分:0)
我实际上认为访客模式会在这里被滥用。相反,这是一种典型的开关类型代码气味,最好由多态性处理。
当你说“如果一个派生类有一个额外的方法来调用”时,那就是假设一个特定的设计。这不是功能要求。功能要求是“如果创建的两个对象中的一个必须在事件Y期间执行行为X”。为什么会有所不同?因为有许多方法可以实现这一点,不需要更多的接口(尽管可能有更多的方法)。
让我举个例子。
你有你的工厂
std::map<ConfigValue, Generator> objectFactory_;
你已经注册了一堆生成器(可能是在类的构造函数中)
RegisterGenerator(configValueA, DummyGenerator);
RegisterGenerator(configValueB, RealGenerator);
...
在某些时候,你想要创建其中一个对象。
shared_ptr<Base> GetConfigObject(ConfigFile config)
{
return objectFactory_[config.a]();
}
然后你想用对象来处理一个事件,你可以做到
void ManagingClass::HandleEventA()
{
theBaseObjectReturned->HandleEventAThroughInterfaceObject(this);
}
注意我是如何传递这个指针的。这意味着如果您有一个对象不想做任何事情(比如进行额外的行为调用),那么您的管理类可能会提供,它不需要使用它。
Object<DummyInterface>::HandleEventAThroughInterfaceObject(ManagingClass *)
{
// just do dummy behavior
}
然后如果你想做一些额外的事情(调用一个新的行为),它可以通过RealInterface中的指针来完成它
Object<RealInterface>::HandleEventAThroughInterfaceObject(ManagingClass * that)
{
that->DoExtraBehavior();
// then dummy - or whatever order
// you could even call multiple methods as needed
}
这是处理多态时应始终采用的基本方法。除了通过调用虚拟调度之外,您不应该为不同类型设置两个不同的代码路径。您永远不应该有两个不同的代码块,一个调用方法A,B和C,另一个只在处理基础对象时调用A和D,具体取决于类型。相反,总是让派生对象做出弄清楚要做什么的工作 - 因为他们知道自己是谁。如果您需要在管理对象中执行操作,请传递一个指针以供它们使用。