2011-08-19 115 views
1

我真的不知道如何制定我的问题,但这里是我试图解决这一难题:从不同类型的模板类创建对象

if (config.a) 
    myObject = new Object<DummyInterface>(); 
else 
    myObject = new Object<RealInterface>(); 

所以任务是创建一个一个对象如果在config中指定了虚拟接口,则使用真实接口类。 那么我该如何声明myObject? 有几个选项,我可以有对象类从抽象类派生无模板:即:

class Base 
{ 
    ... 
} 

template <class T> 
class Object : public Base 
{ 
... 
} 

然后,我可以宣布myObject的是:

Base* myObject; 

但现在的问题是:如果我的对象类声明非虚方法:

template <class T> 
class Object : public Base 
{ 
public: 
    T getInterface() { return myInterface;} 
private: 
    T myInterface; 
} 

我不能把它像这样:

myObject->getInterface() 

,我不能做动态转换,因为我不知道是什么类型,直到运行时...

任何建议如何解决呢?也许有另一种解决方案?

+4

如果您需要将接口投射到实施中,则出现问题。尝试审查你的课程设计。 –

回答

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会得到正确的类型。

+0

比我的好得多:) –

0
if (config.a) 
    myObject = new Object<DummyInterface>(); 
else 
    myObject = new Object<RealInterface>(); 

这种构造在多态性方面是不正确的。 两个模板实例化是两个不同的类。最好的情况是,当你有这样的事情:

template <class T> SomeClass: public SomeBaseClass 
{ 
}; 
......... 
SomeBaseClass* myObject; 

但它带给你没有利润。 最简单和正确的解决方案是虚拟功能。访问者模式似乎也很有用。

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来处理基础对象,具体取决于类型。相反,总是让派生的对象完成确定要做什么的工作 - 因为他们知道他们是谁。如果您需要在管理对象中执行某些操作,请传递一个指针以供它们使用。

+0

要添加更多点:如果您希望我在HandleEventAThroughInterfaceObject中提到的行为使用类型T - 您可以在那里做到这一点。如果您需要将类型T发送到ManagingClass,则可以将其发送到那里(可能调用模板函数)。你需要做的一切,在你知道类型信息的地方做。这是一个比访问者模式要解决的更普遍的问题。你并不总是需要给经理打电话,你没有建立一个添加更多虚拟方法的方法等。这只是基本的多态设计。 – ex0du5

相关问题