2012-10-24 42 views
2

对不起,如果这个问题有点混乱。我真的在寻求学习的目的,看看是否有这样的方式,甚至是可能的。跨多个班级成员功能共享模板参数

在下面的类,我要指定的CreateObject()和GetObject的()的模板参数:

class ObjectManager 
{ 
public: 
    template <class T> 
    void CreateObject(int id) 
    { 
     //Store pointer to newly created object in a map 
    } 

    template <class T> 
    T* GetObject(int id) 
    { 
     //Find object using id and return a T* to it 
    } 
}; 

的CreateObject()使用模板参数来建立正确的对象的类型,然后存储在地图上指向它的指针。 GetObject()使用模板参数来返回所需类型的指针。对于某些对象,我希望GetObject()返回一个指向实际对象类型的指针。对于其他对象,我希望GetObject()返回一个指向父类型的指针。

截至目前,任我打电话GetObject的(),我需要指定类型:

SomeType* pST = m_objectManager.GetObject<SomeType>(id); 
AnotherType* pAT = m_objectManager.GetObject<AnotherType>(id); 

我的目标是指定实际的对象类型,并在所需的返回类型为模板参数我的CreateObject()函数:

class ObjectManager 
{ 
public: 
    template <class T, class DesiredReturnType> 
    void CreateObject(int id) 
    { 
     //Store pointer to newly created object of type T in a map 
     //The DesiredReturnType would be used by GetObject() to return the correct type of pointer 
    } 

    //This isn't possible but would be ideal. 
    DesiredReturnType* GetObject(int id) 
    { 
     //Return a DesiredReturnType* to the object 
    } 
}; 

m_objectManager.CreateObject<SomeType, ParentOfSomeType>(id); 

//Now I don't need to specify a template argument when calling GetObject(). 
//CreateObject() will create a new SomeType. 
//GetObject() will return a ParentOfSomeType* which is really pointing to a SomeType object 
ParentOfSomeType* pPST = m_objectManager.GetObject(id); 

由于每个对象都有不同类型和不同所需的返回类型,我将无法使用类模板参数。类型和所需的返回返回类型总是会根据我创建的对象类型而变化。

会是这样的事情吗?有没有某种设计模式可以帮助解决这种情况?

编辑:

设计选择的原因如下。我将调用另一个具有不同行为的函数,具体取决于是否收到Parent *或Child *。

通过取出模板参数,我想我或许可以这样做:

for(int id = 0; id < 10; id++) 
MyFunction(m_objectManager.GetObject(id)); 

这可能不会改变的事实,这是一个错误的决定的选择,但我主要是出于好奇。 :)

+0

*“对于某些对象,我想GetObject的()返回一个指向实际对象类型对于其他对象,我希望GetObject()返回一个指向父类型的指针。“*看起来像一个糟糕的设计。 – Pubby

+0

这看起来不安全。 – Wug

+0

ObjectManager如何在内部存储对象?它是否将所有对象存储在一张地图中,或者放在不同的地方?它可以从ID中推断出对象类型吗? –

回答

0

什么类模板:

class ObjectManager 
{ 
public: 
    /// reference to some internal object manager 
    template <class T, class DesiredReturnType> 
    class ObjectRef { 
    public: 
    ObjectRef(ObjectManager& manager) {} 
    DesiredReturnType* GetObject() 
    { 
    } 
    }; 
    template <class T, class DesiredReturnType> 
    ObjectRef<T,DesiredReturnType> CreateObject(int id) 
    { 
    } 
}; 

auto ref = m_objectManager.CreateObject<SomeType, ParentOfSomeType>(id); 

//Now I don't need to specify a template argument when calling GetObject(). 
//CreateObject() will create a new SomeType. 
//GetObject() will return a ParentOfSomeType* which is really pointing to a SomeType object 
ParentOfSomeType* pPST = ref.GetObject(); // no need to specify id... 
+0

我不确定你的意思。 'Object <>'这里的实际对象还是更像对象句柄?如果它是实际的对象,那么我就不会看到对象管理器再也无法管理任何东西 - 这可能是OP需要并且无法解决的问题。如果它是一个句柄,那么这可以工作,但我建议使用另一个名字。 –

+0

@PaulGroke可以是对象或对象句柄。我同意/猜测OP想要处理。将解决。 – PiotrNycz

0

C++中的函数只能有一个返回类型,该类型必须在编译时是已知的。函数模板可以有一个依赖于它的模板参数的返回类型。由于C++是静态类型的,因此必须在编译时解析依赖关系。这意味着您无法在运行时从地图查找所需的返回类型。但是,您可以从模板参数中派生它。

编辑:澄清:当您“使用”功能模板,如FunctionTemplate<Type>()FunctionTemplate(parameterThatsUsedToDeriveTheTemplateArguments),函数模板被实例化。这意味着将会创建一个名为FunctionTemplate<ARG1, ARG2, ...>的正常函数 - 对于参数ARG1,ARG2等模板的所谓“特殊化”。此函数就像一个普通函数,这意味着它也可以只有一个函数在编译时必须知道的固定返回类型。 /编辑

换句话说:GetObject必须至少有一个模板参数,它用来派生返回类型。有一件事可以工作 - 取决于你想如何使用它 - 将编码id参数类型中所需的返回类型。

E.g.像

template <class T> 
struct ObjectId { 
    typedef T ReturnType; 
    ObjectId(int id) : m_id(id) {} 
    int m_id; 
}; 

class ObjectManager { 
    ... 
    template <class T, class ID> // ID type will be deduced 
    void CreateObject(ID id) { 
     ... 
    } 

    template <class ID> // ID type will be deduced 
    typename ID::ReturnType* GetObject(ID id) { 
     ... 
    } 
}; 

... 
ObjectManager obman; 
auto const idFoo = ObjectId<Foo>(1); 
auto const idBar = ObjectId<BarBase>(2); 

obman.CreateObject<Foo>(idFoo); 
obman.CreateObject<Bar>(idBar); 
Foo* foo = obman.GetObject(idFoo); 
BarBase* bar = obman.GetObject(idBar); 
0

尝试访问者模式。 Live example at Ideone.com

struct ConcreteVisitor: IVisitor 
{ 
    virtual void visit(int) 
    { 
     cout << "visiting int" << endl; 
    } 
    virtual void visit(double) 
    { 
     cout << "visiting double" << endl; 
    } 
    virtual void visit(SomeClass&) 
    { 
     cout << "visiting SomeClass" << endl; 
    } 
    // .. 
}; 
int main(int argc,char *argv[]) 
{ 
    ObjectManager manager; 
    ConcreteVisitor visitor; 

    manager.create_object<int>(1); 
    manager.create_object<double>(2); 
    manager.create_object<SomeClass>(3); 

    manager.apply(1,visitor); 
    manager.apply(2,visitor); 
    manager.apply(3,visitor); 
    return 0; 
} 

输出是:

SomeClass::SomeClass() 
visiting int 
visiting double 
visiting SomeClass 
SomeClass::~SomeClass() 

全码:

#include <boost/shared_ptr.hpp> 
#include <boost/ptr_container/ptr_map.hpp> 
#include <iostream> 
#include <ostream> 
#include <map> 

using namespace std; 
using namespace boost; 
typedef int ID; 

struct SomeClass 
{ 
    SomeClass() 
    { 
     cout << "SomeClass::SomeClass()" << endl; 
    } 
    ~SomeClass() 
    { 
     cout << "SomeClass::~SomeClass()" << endl; 
    } 
}; 

struct IVisitor 
{ 
    virtual void visit(int)=0; 
    virtual void visit(double)=0; 
    virtual void visit(SomeClass&)=0; 
    // .. 
}; 

struct ConcreteVisitor: IVisitor 
{ 
    virtual void visit(int) 
    { 
     cout << "visiting int" << endl; 
    } 
    virtual void visit(double) 
    { 
     cout << "visiting double" << endl; 
    } 
    virtual void visit(SomeClass&) 
    { 
     cout << "visiting SomeClass" << endl; 
    } 
    // .. 
}; 

struct ITypeStorage 
{ 
    virtual void apply_visitor(void *obj,IVisitor &visitor)=0; 
}; 

template<typename ObjectType> struct TypeStorage: ITypeStorage 
{ 
    virtual void apply_visitor(void *obj,IVisitor &visitor) 
    { 
     visitor.visit(*(static_cast<ObjectType *>(obj))); 
    } 
}; 

class ObjectManager 
{ 
    map<ID,boost::shared_ptr<void> > objects; 
    ptr_map<ID,ITypeStorage> types; 
public: 
    template <class T> 
    void create_object(ID id) 
    { 
     objects[id].reset(new T());//shared_ptr will use right deleter 
     types.insert(id,new TypeStorage<T>()); 
    } 
    void apply(ID id,IVisitor &visitor) 
    { 
     types.find(id)->second->apply_visitor(objects[id].get(),visitor); 
    } 
}; 

int main(int argc,char *argv[]) 
{ 
    ObjectManager manager; 
    ConcreteVisitor visitor; 

    manager.create_object<int>(1); 
    manager.create_object<double>(2); 
    manager.create_object<SomeClass>(3); 

    manager.apply(1,visitor); 
    manager.apply(2,visitor); 
    manager.apply(3,visitor); 
    return 0; 
}