Шаблонный класс C ++, ссылающийся на себя

Мне нужно создать архитектуру MVC, где классы View и Controller уже были написаны в виде шаблонов следующим образом:

template<class Model, class View>
class Controller { /* Implement Controller */ };

template<class Model, class Controller>
class View { /* Implement View */ };

У меня также есть модельный класс:

class Model { /* Implement Model */ };

Я не контролирую, как создаются классы Model, View и Controller. Теперь, как мне создать экземпляр контроллера или представления?

Чтобы лучше объяснить ситуацию, если я хочу создать Controller с использованием классов View и Model выше (мне НЕ разрешено использовать какие-либо другие классы), я получаю:

ПРИМЕЧАНИЕ: неверный код C ++ следует

Controller< Model, View< Model, // ad infinitum

тогда как следующее также недействительно:

ПРИМЕЧАНИЕ: неверный код C ++ следует

Controller< Model, View< Model, Controller > > c;

3

Решение

Это возможная реализация

template<typename View, typename Model>
struct Controller {
View *view;
Model *model;

Controller() : view(0), model(0) {}
void setUp(View *v, Model *m) {
view = v;
model = m;
}

virtual void change() = 0;
};

template<typename Controller, typename Model>
struct View {
Controller *controller;
Model *model;

View() : controller(0), model(0) {}
void setUp(Controller *c, Model *m) {
controller = &c;
model = &m;
}

virtual void display() = 0;
};

Для создания экземпляра трюк заключается в извлечении класса из шаблона, в котором в качестве параметра указан объявленный класс:

struct MyModel {
int x;
MyModel(int x) : x(x) {}
};

struct MyController;
struct MyView : View<MyController, MyModel>
{
void display() { std::cout << model->x << std::endl; }
};

struct MyController : Controller<MyView, MyModel>
{
void change() { model->x = 44; }
};

После этого вы можете создавать экземпляры и настраивать их

int main(int argc, const char *argv[]) {
MyModel m(42);
MyView v;
MyController c;
v.setUp(&c, &m); c.setUp(&v, &m);

v.display();
c.change();
v.display();

return 0;
}
3

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

Это компилирует:

class MyView;
class MyController: public Controller<Model,MyView>{};
class MyView: public View<Model,MyController>{};
MyController myC;
MyView myV;

Но это зависит от того, как написаны Controller и / или View. MyView является неполным на момент получения MyController, поэтому можно использовать только указатели.

3

Ты не сможешь это сделать. Несколько мыслей, чтобы вы пошли:

  • Используйте шаблоны только для определенных функций-членов

    Если вашим классам не нужно хранить элементы данных, вы можете написать:

    template<class Model>
    class Controller {
    public:
    void foo() // does not need View
    { ... }
    
    template<typename View>
    void bar(const View& v) // works with a specific View
    { ... }
    };
    
  • возможно Controller не нужно знать View?

    template<class Model> // no dependency on View
    class Controller { /* Implement Controller */ };
    template<class Model, class Controller>
    class View { /* Implement View */ };
    // no it works
    Controller<MyModel> ctrl;
    View<MyModel, Controller<MyModel>> view;
    
  • Используйте интерфейс:

    class IController { ... };
    class IView { ... };
    template<class Model>
    class Controller : public IController { /* Implement Controller */ };
    template<class Model>
    class View : public IView { /* Implement View */ };
    
  • Получите типы из ваших типов шаблонов:

    class MyView;
    class MyController : public Controller<MyModel,MyView> { };
    class MyView : public View<MyModel,MyController> { };
    

    Здесь вы должны иметь в виду эту проблему: Два шаблонных класса состоят из членов друг друга

1
По вопросам рекламы [email protected]