【问题标题】:C++ template class referring to itself引用自身的 C++ 模板类
【发布时间】:2026-01-08 17:00:01
【问题描述】:

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

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

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

注意:后面的 C++ 代码无效

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

而以下内容也是无效的:

注意:后面的 C++ 代码无效

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

【问题讨论】:

  • 如何将any C++ 类实例化为实例?您可能需要重新考虑您要问的内容,因为它几乎可以按原样模糊不清(并且唯一远程有效的 C++ 是Model;控制器和视图模板都缺少模板参数,我很确定这将与此相关)。
  • 另外,“自我参照”是什么意思?
  • 你能提供一些真实的编译代码示例吗?您显示的代码甚至不是有效的 C++。
  • 小于没有被转义@jww 谢谢
  • 对不起,但我看不出这是不是有效的 C++ 代码?你能解释一下这个问题吗?

标签: c++ templates model-view-controller self-reference


【解决方案1】:

这是一个可能的实现

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

【讨论】:

  • 非常感谢。这对我有用。我会投票给你,但没有必要的代表。
  • +1 这非常接近我拼凑的,which I will link here。我没有为功能样本付出额外的努力,只是设置。很高兴我不是唯一一个看到这样的东西的人。
【解决方案2】:

这确实编译:

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

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

【讨论】:

  • 哇,这真的可以编译!编写类定义时可以使用前向声明的类作为模板参数吗?这对我来说是新知识!我在 Controller 和 View 中编写了一些虚拟函数,并从 Controller 中调用了 View 函数 - 它可以工作!!!
  • 对不起,我将@6502 的答案标记为正确答案,因为它更详细。但是你说的是对的。我会投票给你,但不幸的是,我没有必要的代表。非常感谢您的帮助。
  • @vvvcvvcv 它编译是因为在实际的 MyController 和 MyView 类中没有任何对象使用。除非将所有内容都仔细设置为引用和/或指针,否则事情会迅速恶化。
  • @WhozCraig 必须假设这双鞋的设计师知道 'e 在做什么。我在回答中提出了警告:Controller 中只有 View*!
【解决方案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> { };
    

    这里你要注意这个问题:Two template classes being composed of a member of each other

【讨论】:

  • 你是说C++的设计者?这不是“错误”,而是模板的工作方式。
  • 在进一步讨论后删除了我之前的 cmets。您的解决方案间接起作用,因此不会对您投反对票。