2012-11-06 41 views
2

我使用recursive template idiom來自動在工廠中註冊基類的所有子類。但是在我的設計中,子類必須具有基類的朋友類。由於我的基類的構造函數應該是私有的,以避免通過工廠以外的類實例化。遞歸模板成語如何避免基類是子類的朋友

總體目標是在BaseSolver中完成工廠註冊,並且ChildClasses不能通過工廠實例化。

這裏是我的基類的代碼,它會自動註冊SolverFactory中的所有子代。

template<class T> 
struct BaseSolver: AbstractSolver 
{ 
protected: 
    BaseSolver() 
    { 
     reg=reg;//force specialization 
    } 
    virtual ~BaseSolver(){} 
    /** 
    * create Static constructor. 
    */ 
    static AbstractSolver* create() 
    { 
     return new T; 
    } 

    static bool reg; 
    /** 
    * init Registers the class in the Solver Factory 
    */ 
    static bool init() 
    { 
     SolverFactory::instance().registerType(T::name, BaseSolver::create); 
     return true; 
    } 
}; 

template<class T> 
bool BaseSolver<T>::reg = BaseSolver<T>::init(); 

在這裏,我的子類的頭文件:

class SolverD2Q5 : public BaseSolver<SolverD2Q5>{ 

private: 
    //how can I avoid this? 
    friend class BaseSolver; 

    SolverD2Q5(); 

    static const std::string name; 

} 

這工作得很好。不過,我真的不喜歡將BaseSolver添加爲朋友類,但我不要希望構造函數和靜態成員名稱是公開的。

有沒有更優雅的解決方案或更好的佈局來避免這種情況?

+0

爲什麼BaseSolver需要成爲朋友類?你可以添加'朋友類T'到BaseSolver嗎? –

+0

這應該如何幫助我不想訪問BaseSolver中的私有方法,但BaseSolver應該訪問Solver的私有成員。 – tune2fs

+0

我喜歡這種設計。爲什麼'朋友'聲明是一個問題? – aschepler

回答

0

更新: 我相信這個技巧還沒有被理解,因此我現在創建了完整的解決方案。這只是對OP代碼的一個小改動。只需將BaseSolver中的T替換爲從T派生的空類定義即可。

原始文本: 我想你可以通過委派友誼的包裝類是私有的基礎求解做到這一點。這個類將繼承於任何要創建實例的類。編譯器應該優化包裝類。

#include <iostream> 
#include <map> 

struct AbstractSolver { virtual double solve() = 0; }; 

class SolverFactory 
{ 
    std::map<char const * const, AbstractSolver * (*)()> creators; 
    std::map<char const * const, AbstractSolver *> solvers; 
public: 
    static SolverFactory & instance() 
    { 
     static SolverFactory x; 
     return x; 
    } 
    void registerType(char const * const name, AbstractSolver *(*create)()) 
    { 
     creators[name] = create; 
    } 
    AbstractSolver * getSolver(char const * const name) 
    { 
     auto x = solvers.find(name); 
     if (x == solvers.end()) 
     { 
      auto solver = creators[name](); 
      solvers[name] = solver; 
      return solver; 
     } 
     else 
     { 
      return x->second; 
     } 
    } 
}; 

template<class T> class BaseSolver : public AbstractSolver 
{ 
    struct Wrapper : public T { // This wrapper makes the difference 
     static char const * const get_name() { return T::name; } 
    }; 
protected: 
    static bool reg; 
    BaseSolver() { 
     reg = reg; 
    } 
    virtual ~BaseSolver() {} 
    static T * create() { 
     return new Wrapper; // Instantiating wrapper instead of T 
    } 
    static bool init() 
    { 
     SolverFactory::instance().registerType(Wrapper::get_name(), (AbstractSolver * (*)())BaseSolver::create); 
     return true; 
    } 
}; 

template<class T> 
bool BaseSolver<T>::reg = BaseSolver<T>::init(); 

struct SolverD2Q5 : public BaseSolver<SolverD2Q5> 
{ 
public: 
    double solve() { return 1.1; } 
protected: 
    SolverD2Q5() {} // replaced private with protected 
    static char const * const name; 
}; 
char const * const SolverD2Q5::name = "SolverD2Q5"; 

struct SolverX : public BaseSolver<SolverX> 
{ 
public:  
    double solve() { return 2.2; } 
protected: 
    SolverX() {} // replaced private with protected 
    static char const * const name; 
}; 
char const * const SolverX::name = "SolverX"; 

int main() 
{ 
    std::cout << SolverFactory::instance().getSolver("SolverD2Q5")->solve() << std::endl; 
    std::cout << SolverFactory::instance().getSolver("SolverX")->solve() << std::endl; 
    std::cout << SolverFactory::instance().getSolver("SolverD2Q5")->solve() << std::endl; 
    std::cout << SolverFactory::instance().getSolver("SolverX")->solve() << std::endl; 

    char x; 
    std::cin >> x; 
    return 0; 
}