2012-11-06 1 views
2

recursive template idiom을 사용하여 팩토리에서 기본 클래스의 모든 자식을 자동으로 등록합니다. 그러나 내 디자인에서 자식 클래스 친구 클래스로 기본 클래스가 있어야합니다. 팩토리를 통하는 것이 아니라이 클래스의 인스턴스 생성을 피하기 위해, Base 클래스의 생성자가 private이어야한다.재귀 템플릿 관용구 기본 클래스가 자식 클래스의 친구가되는 것을 피하는 방법

과도한 목표는 공장 등록이 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를 추가해야하는 것을 싫어하지만, 나는 을 가지고 있지 않다.은 public이 될 생성자와 정적 멤버 이름이 필요하다.

더 좋은 해결책이나 더 나은 레이아웃이 없습니까?

+0

왜 BaseSolver가 친구 클래스 여야합니까? BaseSolver에'friend class T'를 대신 추가 할 수 있습니까? –

+0

어떻게하면 BaseSolver의 private 메소드에 액세스하고 싶지는 않지만 BaseSolver는 Solver의 private 멤버에 액세스해야합니다. – 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; 
} 
관련 문제