2013-05-06 66 views
0

我正在使用C++ 98。我想創建一個基於模板的通用工廠,創建者可以不帶參數來創建目標對象或一個參數。如何創建基於通用模板的工廠?

/*<class.h> begins 

#ifndef INCLUDED_CLASS 
#define INCLUDED_CLASS 

#include <iostream> 
#include <boost/shared_ptr.hpp> 

class A 
{ 
public: 
    A() { _a = 27; } 
    void print() const { std::cout << "A is " << _a << "." << std::endl; } 
protected: 
    int _a; 
}; 
typedef boost::shared_ptr<A> APtr; 

class AA : public A 
{ 
public: 
    void print() const { std::cout << "AA is " << _a << "!" << std::endl; } 
}; 

class B 
{ 
public: 
    B(double b) { _b = b; } 
    void print() const { std::cout << "B is " << _b << "." << std::endl; } 
protected: 
    double _b; 
}; 
typedef boost::shared_ptr<B> BPtr; 

class BB : public B 
{ 
public: 
    BB(double b) : B(b) {}; 
    void print() const { std::cout << "BB is " << _b << "!" << std::endl; } 
}; 

#endif 

/*<class.h> ends 



/*<factory.h> begins 

#ifndef INCLUDED_FACTORY 
#define INCLUDED_FACTORY 

#include <map> 
#include <string> 
#include <boost/shared_ptr.hpp> 

template<class bT, class pT=void> 
class Creator 
{ 
public: 
    virtual bT* create() = 0; 
    virtual bT* create(const pT* param) = 0; 
}; 

template <class bT, class pT> 
struct CreatorPtr 
{ 
    typedef boost::shared_ptr< Creator<bT> > type; 
}; 


template <class bT, class cT, class pT> 
class CreatorImpl : public Creator<bT, pT> 
{ 
public: 
    virtual bT* create() { return new cT; } 
    virtual bT* create(const pT* param) { return new cT(param); } 
}; 


template<class bT, class pT=void> 
class Factory 
{ 
public: 
    virtual bT* create(const std::string& name) const = 0; 
    virtual bT* create(const std::string& name, const pT* param) const = 0; 
protected: 
    Factory() {} 
    Factory(const Factory&) {} 
    Factory &operator=(const Factory&) { return *this; } 
    void registerCreator(const std::string& name, typename CreatorPtr<bT, pT>::type creator) 
     { _table_creator[name] = creator; } 
    typedef std::map<std::string, typename CreatorPtr<bT, pT>::type> tableCreator; 
    typedef typename tableCreator::const_iterator citerTc; 
    citerTc begin() const { return _table_creator.begin(); } 
    citerTc end() const { return _table_creator.end(); } 
    citerTc find(const std::string& name) const { return _table_creator.find(name); } 
protected: 
    tableCreator _table_creator; 
}; 

class A; 
class EngineA : public Factory<A> 
{ 
public: 
    virtual A* create(const std::string& name) const 
    { 
     citerTc it = find(name); 
     if (it != end() && it->second) 
     { 
      return it->second->create(); 
     } 
     else 
      return (A*)NULL; 
    } 

    static Factory<A>& get() 
    { 
     static EngineA instance; 
     instance.registerEngine(); 
     return instance; 
    } 
private: 
    virtual A* create(const std::string& name, const void* param) const { return (A*)NULL; } 
private: 
    virtual void registerEngine(); 
}; 

void EngineA::registerEngine() 
{ 
    CreatorPtr<A, void>::type AACreator(new CreatorImpl<A, AA, void>); 
    registerCreator("AA", AACreator); 
} 

class B; 
class EngineB : public Factory<B, double> 
{ 
public: 
    virtual B* create(const std::string& name, const double* value) const 
    { 
     citerTc it = find(name); 
     if (it != end() && it->second && value) 
     { 
      return it->second->create(value); 
     } 
     else 
      return (B*)NULL; 
    } 

      static Factory<B, double>& get() 
    { 
     static EngineB instance; 
     instance.registerEngine(); 
     return instance; 
    } 
private: 
    virtual B* create(const std::string& name) const { return (B*)NULL; } 
private: 
    virtual void registerEngine(); 
}; 

void EngineB::registerEngine() 
{ 
    CreatorPtr<B, double>::type BBCreator(new CreatorImpl<B, BB, double>); 
    registerCreator("BB", BBCreator); 
} 

#endif 

/*<factory.h> ends 



/*<main.cpp> begins 

#include <class.h> 
#include <factory.h> 

int main(void) 
{ 
    APtr a(EngineA::get().create("AA")); 
    if (a) 
     a->print(); 

    double value = 35.7; 
    BPtr b(EngineB::get().create("BB",&value)); 
    if (b) 
     b->print(); 

    return 0; 
} 

/*<main.cpp> ends 

的編譯錯誤是:

....../boost//boost_1_46_1/include/boost/smart_ptr/shared_ptr.hpp: In constructor ‘boost::shared_ptr<T>::shared_ptr(Y*) [with Y = CreatorImpl<B, BB, double>, T = Creator<B, void>]’: 
./factory.h:116: instantiated from here 
....../boost//boost_1_46_1/include/boost/smart_ptr/shared_ptr.hpp:187: error: cannot convert ‘CreatorImpl<B, BB, double>*’ to ‘Creator<B, void>*’ in initialization 
./factory.h: In member function ‘bT* CreatorImpl<bT, cT, pT>::create() [with bT = B, cT = BB, pT = double]’: 
main.cpp:15: instantiated from here 
./factory.h:27: error: no matching function for call to ‘BB::BB()’ 
./class.h:36: note: candidates are: BB::BB(double) 
./class.h:34: note:     BB::BB(const BB&) 
./factory.h: In member function ‘bT* CreatorImpl<bT, cT, pT>::create(const pT*) [with bT = B, cT = BB, pT = double]’: 
main.cpp:15: instantiated from here 
./factory.h:28: error: no matching function for call to ‘BB::BB(const double*&)’ 
./class.h:36: note: candidates are: BB::BB(double) 
./class.h:34: note:     BB::BB(const BB&) 
./factory.h: In member function ‘bT* CreatorImpl<bT, cT, pT>::create(const pT*) [with bT = A, cT = AA, pT = void]’: 
main.cpp:15: instantiated from here 
./factory.h:28: error: no matching function for call to ‘AA::AA(const void*&)’ 
./class.h:18: note: candidates are: AA::AA() 
./class.h:18: note:     AA::AA(const AA&) 
make: *** [test] Error 1 

任何人都可以用錯誤的幫助?這是創建通用模板工廠的好方法嗎?

+0

這可能會幫助您開始:http://stackoverflow.com/questions/16047560/creating-dynamic-type-in​​-c/16047779#16047779 - 完全不需要太多的模板。 – paddy 2013-05-06 22:16:13

+0

謝謝稻田。但是這並沒有解決我的問題。基本上我已經有了工廠,但我只是想重用它來適應創建一個具有零個或一個輸入參數的類。 – user2355104 2013-05-06 22:46:04

+0

如果您發佈的代碼完全從您的項目中複製,則您使用了錯誤的評論語法。對於單行註釋,請使用'//'而不是'/ *'。 – paddy 2013-05-06 23:05:49

回答

0

第一個錯誤:

typedef boost::shared_ptr< Creator<bT> > type; 

你忘傳遞點:

typedef boost::shared_ptr< Creator<bT,pT> > type; 

第二:

virtual bT* create(const pT* param) { return new cT(param); } 

要麼接受創建引用,或通過取消引用指針到構造函數:

virtual bT* create(const pT& param) { return new cT(param); } // and change the other parts of the code accordingly to accept reference instead of pointer 
// or: 
virtual bT* create(const pT* param) { return new cT(*param); } 

更大的問題是,在這種方法中,兩個版本的create都是爲給定的cT生成的,並且由於缺少構造函數重載而不會編譯。

專門針對void,並且只保留有意義的創建過載。這種方法的工作原理:

#ifndef INCLUDED_CLASS 
#define INCLUDED_CLASS 

#include <iostream> 
#include <boost/shared_ptr.hpp> 


class A 
{ 
public: 
    A() { _a = 27; } 
    void print() const { std::cout << "A is " << _a << "." << std::endl; } 
protected: 
    int _a; 
}; 
typedef boost::shared_ptr<A> APtr; 

class AA : public A 
{ 
public: 
    void print() const { std::cout << "AA is " << _a << "!" << std::endl; } 
}; 

class B 
{ 
public: 
    B(double b) { _b = b; } 
    void print() const { std::cout << "B is " << _b << "." << std::endl; } 
protected: 
    double _b; 
}; 
typedef boost::shared_ptr<B> BPtr; 

class BB : public B 
{ 
public: 
    BB(double b) : B(b) {}; 
    void print() const { std::cout << "BB is " << _b << "!" << std::endl; } 
}; 

#endif 

// ---- 

#ifndef INCLUDED_FACTORY 
#define INCLUDED_FACTORY 

#include <map> 
#include <string> 
#include <boost/shared_ptr.hpp> 

template<class bT, class pT = void> 
class Creator 
{ 
public: 
    virtual bT* create(const pT* param) = 0; 
}; 

template<class bT> 
class Creator<bT> 
{ 
public: 
    virtual bT* create() = 0; 
}; 

template <class bT, class pT = void> 
struct CreatorPtr 
{ 
    typedef boost::shared_ptr< Creator<bT,pT> > type; 
}; 
template <class bT> 
struct CreatorPtr<bT> 
{ 
    typedef boost::shared_ptr< Creator<bT> > type; 
}; 


template <class bT, class cT, class pT = void> 
class CreatorImpl : public Creator<bT, pT> 
{ 
public: 
    virtual bT* create(const pT* param) { return new cT(*param); } 
}; 
template <class bT, class cT> 
class CreatorImpl<bT,cT> : public Creator<bT> 
{ 
public: 
    virtual bT* create() { return new cT; } 
}; 

template<class CreatorPtrType> 
class FactoryBase 
{ 
protected: 
    FactoryBase() {} 
    FactoryBase(const FactoryBase&) {} 
    FactoryBase &operator=(const FactoryBase&) { return *this; } 
    void registerCreator(const std::string& name, CreatorPtrType creator) 
    { _table_creator[name] = creator; } 
    typedef std::map<std::string, CreatorPtrType> tableCreator; 
    typedef typename tableCreator::const_iterator citerTc; 
    citerTc begin() const { return _table_creator.begin(); } 
    citerTc end() const { return _table_creator.end(); } 
    citerTc find(const std::string& name) const { return _table_creator.find(name); } 
protected: 
    tableCreator _table_creator; 
}; 


template<class bT, class pT = void> 
class Factory : public FactoryBase<typename CreatorPtr<bT, pT>::type> 
{ 
public: 
    virtual bT* create(const std::string& name, const pT* param) const = 0; 
}; 
template<class bT> 
class Factory<bT> : public FactoryBase<typename CreatorPtr<bT>::type> 
{ 
public: 
    virtual bT* create(const std::string& name) const = 0; 
}; 

class A; 
class EngineA : public Factory<A> 
{ 
public: 
    virtual A* create(const std::string& name) const 
    { 
     citerTc it = find(name); 
     if (it != end() && it->second) 
     { 
      return it->second->create(); 
     } 
     else 
      return (A*)NULL; 
    } 

    static Factory<A>& get() 
    { 
     static EngineA instance; 
     instance.registerEngine(); 
     return instance; 
    } 
private: 
    virtual void registerEngine(); 
}; 

void EngineA::registerEngine() 
{ 
    CreatorPtr<A>::type AACreator(new CreatorImpl<A, AA>); 
    registerCreator("AA", AACreator); 
} 

class B; 
class EngineB : public Factory<B, double> 
{ 
public: 
    virtual B* create(const std::string& name, const double* value) const 
    { 
     citerTc it = find(name); 
     if (it != end() && it->second && value) 
     { 
      return it->second->create(value); 
     } 
     else 
      return (B*)NULL; 
    } 

    static Factory<B, double>& get() 
    { 
     static EngineB instance; 
     instance.registerEngine(); 
     return instance; 
    } 
private: 
    virtual void registerEngine(); 
}; 

void EngineB::registerEngine() 
{ 
    CreatorPtr<B, double>::type BBCreator(new CreatorImpl<B, BB, double>); 
    registerCreator("BB", BBCreator); 
} 

#endif 

// ---- 

#include <class.h> 
#include <factory.h> 

int main(void) 
{ 
    APtr a(EngineA::get().create("AA")); 
    if (a) 
     a->print(); 

    double value = 35.7; 
    BPtr b(EngineB::get().create("BB",&value)); 
    if (b) 
     b->print(); 

    return 0; 
} 
+0

謝謝。它編譯和工作。您能否告訴我如何按照該順序安裝Creator類,是否像第二個類似於前一個類的特例? – user2355104 2013-05-07 14:25:51

+0

是的,這是部分專業化。部分原因是仍然存在一些模板參數。專業化,因爲一些參數是固定的。 一般聲明是: template class Creator; 專業化是: 模板 類造物主 這相當於: 模板 類造物主 因爲默認的說法。 這裏pT被固定爲無效,而bT仍然是一個參數。 該實現涵蓋了pT無效的任何bT。 對於任何其他情況,通用版本將被實例化。 – jmihalicza 2013-05-07 17:34:20

+0

謝謝。這對我來說非常合適,並且受過良好的教育! – user2355104 2013-05-07 18:00:46