我使用 recursive template idiom在工厂中自动注册基类的所有子类。但是在我的设计中,子类必须将基类作为 friend 类。因为我的基类的构造函数应该是私有(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 添加为友元类,但是我不希望构造函数和静态成员名称公开。
是否有更优雅的解决方案或更好的布局来避免这种情况?
最佳答案
更新:
我相信这个技巧还没有被理解,因此我现在创建了完整的解决方案。这只是对 OP 代码的一点改动。只需将 BaseSolver
中的 T 替换为派生自 T
的空类定义即可。
原文: 我认为您可以通过将友元委托(delegate)给基础求解器私有(private)的包装类来实现。此类将继承自要为其创建实例的任何类。编译器应该优化包装类。
#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;
}
关于c++ - 递归模板成语如何避免基类是子类的 friend ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13249073/