C++引用自身的模板类

C++ template class referring to itself

本文关键字:引用 C++      更新时间:2023-10-16

我需要创建一个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 */ };

我无法控制模型、视图和控制器类的创建方式。现在,如何实例化控制器或视图?

为了更好地解释这种情况,如果我想使用上面的视图和模型类创建一个控制器(我不允许使用任何其他类),我得到:

注意:以下代码无效C++

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

而以下内容也是无效的:

注意:以下代码无效C++

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

这是一个可能的实现

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;
}

确实可以编译:

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

但这取决于控制器和/或视图的编写方式。MyView 在派生 MyController 时不完整,因此只能使用指针。

你不能

这样做。让你开始的一些想法:

  • 仅对特定成员函数使用模板

    如果你的类不需要保存数据成员,你可以编写:

    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> { };
    

    在这里,您必须注意此问题:两个模板类由彼此的成员组成