Рекурсивный шаблон идиома, как избежать того, чтобы базовый класс был другом дочерних классов

Я использую рекурсивная идиома шаблона автоматически регистрировать всех детей базового класса на фабрике. Однако в моем дизайне дочерний класс должен иметь в качестве друга класс базового класса. Поскольку конструктор моего базового класса должен быть закрытым, чтобы избежать создания экземпляров этого класса, кроме как через фабрику.

Общая цель состоит в том, чтобы регистрация фабрики выполнялась в 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 как класс друга, однако я не делайте хотите, чтобы конструктор и имя статического члена были публичными.

Есть ли более элегантное решение или лучший макет, чтобы избежать этого?

2

Решение

ОБНОВИТЬ:
Я считаю, что трюк не был понят, поэтому я создал полное решение сейчас. Это всего лишь одно небольшое изменение в коде ОП. Просто замените Т в BaseSolver с пустым определением класса, полученным из 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;
}
0

Другие решения

Других решений пока нет …