C++ 声明/定义顺序依赖关系

C++ 声明/定义顺序依赖关系,c++,class,gcc,forward-declaration,C++,Class,Gcc,Forward Declaration,我有一个这样的代码(C++): 正如你所看到的那样,这是一个不断上升的地狱。正如您所知,这段代码不会编译,除非我在模型之前为window提供一个转发声明,一般来说这样做是不合理的,因为上面的代码不是全部代码,而且代码也会扩展 有没有系统的方法来解决这个问题 除非我为windowbefore模型提供一个前向声明,一般来说这样做是不合理的 事实上,是的。您应该尽可能使用前向声明,而不是包含或完整定义 但最重要的是,至少你的设计看起来有些古怪 编辑:每个请求,带有转发声明的代码: namespace

我有一个这样的代码(C++):

正如你所看到的那样,这是一个不断上升的地狱。正如您所知,这段代码不会编译,除非我在模型之前为
window
提供一个转发声明,一般来说这样做是不合理的,因为上面的代码不是全部代码,而且代码也会扩展

有没有系统的方法来解决这个问题

除非我为windowbefore模型提供一个前向声明,一般来说这样做是不合理的

事实上,是的。您应该尽可能使用前向声明,而不是包含或完整定义

但最重要的是,至少你的设计看起来有些古怪

编辑:每个请求,带有转发声明的代码:

namespace ui
{
    class window;
}
namespace models
{
    class model
    {
        private:
            ui::window* win;
    };
}

//required if this is in a different file
namespace models
{
    class model;
}
namespace ui
{
    class window
    {
        private:
            models::model* modl;
    };
}
除非我为windowbefore模型提供一个前向声明,一般来说这样做是不合理的

事实上,是的。您应该尽可能使用前向声明,而不是包含或完整定义

但最重要的是,至少你的设计看起来有些古怪

编辑:每个请求,带有转发声明的代码:

namespace ui
{
    class window;
}
namespace models
{
    class model
    {
        private:
            ui::window* win;
    };
}

//required if this is in a different file
namespace models
{
    class model;
}
namespace ui
{
    class window
    {
        private:
            models::model* modl;
    };
}

接下来是打破循环依赖的解决方案。
这将更加灵活

namespace models
{
    class modelUser
    {
       virtual void handleModelUpdate() = 0;
       virtual ~modelUser
    }
    class model
    {
        public:
            model(modelUser* user) : mUser(user) { }
        private:
            modelUser* mUser;
    };
}

namespace ui
{
    class window: public models::modelUser
    {
        private:
            models::model* modl;
            virtual void handleModelUpdate() { std::cout << "update from model\n"; }
    };
}
命名空间模型
{
类模型用户
{
虚拟void handleModelUpdate()=0;
虚拟用户
}
类模型
{
公众:
模型(modelUser*user):缪斯(user){}
私人:
模型用户*mUser;
};
}
名称空间用户界面
{
类窗口:公共模型::modelUser
{
私人:
模型::模型*modl;

virtualvoid handleModelUpdate(){std::cout下一步将是打破循环依赖关系的解决方案。
这将更加灵活

namespace models
{
    class modelUser
    {
       virtual void handleModelUpdate() = 0;
       virtual ~modelUser
    }
    class model
    {
        public:
            model(modelUser* user) : mUser(user) { }
        private:
            modelUser* mUser;
    };
}

namespace ui
{
    class window: public models::modelUser
    {
        private:
            models::model* modl;
            virtual void handleModelUpdate() { std::cout << "update from model\n"; }
    };
}
命名空间模型
{
类模型用户
{
虚拟void handleModelUpdate()=0;
虚拟用户
}
类模型
{
公众:
模型(modelUser*user):缪斯(user){}
私人:
模型用户*mUser;
};
}
名称空间用户界面
{
类窗口:公共模型::modelUser
{
私人:
模型::模型*modl;


虚拟void handleModelUpdate(){std::cout not create cyclic dependencies通常是最好的解决方案。这取决于类的功能。我会让你弄清楚设计。通常,循环设计的思维方式有什么问题?它不应该出现在计算机编程领域的任何设计中吗?当然,在它们工作的地方都存在设计k、 但通常情况下,它们不值得麻烦。维基百科页面列出了一些问题:不创建循环依赖通常是最好的解决方案。这取决于类的功能。我会让你了解设计。循环设计的思维方式通常有什么错?它不应该出现在任何设计中吗并非所有的设计都是在计算机编程领域?当然,在它们工作的地方存在设计,但通常它们不值得它们带来的麻烦。维基百科页面列出了一些问题:那么,你会为这个问题提出什么样的设计?没有投反对票,但上面的OP声明不是全部代码,而且代码也会扩展。Fo只要编译器不需要知道类型的内存布局,rward声明就可以工作。考虑到完全扩展的代码不能只处理前向声明。OP要求系统化地解决这个问题吗?@ai64您的问题没有问题,只有一些相互依赖的类。@ai64:使用抽象interfaces将是一个良好的开端;让模型与抽象的
视图
接口交互,而不是与具体的
ui::window
类交互。不可能为嵌入式结构/类创建循环依赖项(语法上和逻辑上),但像这样的循环指针是绝对正常的做法,对于许多树/列表/图形类型的数据结构来说是完全必要的。它们的实现方式与@LuchianGrigore的答案完全相同。事实上,语法的定义正是为了这个目的(即模块化抽象)。那么,你会为这个问题提出什么样的设计?没有否决,但上面的OP声明不是完整的代码,而且代码将进行扩展。只有在编译器不需要知道类型的内存布局的情况下,前向声明才有效。考虑到完全扩展的代码不能只处理前向声明。OP i“你的问题没有问题,只有一些相互依赖的类。@ai64:使用抽象接口将是一个良好的开端;让模型与抽象的
视图
接口交互,而不是与具体的
ui::window
类交互。不可能创建循环。”嵌入式结构/类(语法和逻辑)的r依赖关系,但像这样的循环指针是绝对正常的做法,对于许多树/列表/图形类型的数据结构来说是完全必要的。它们的实现与@LuchianGrigore的答案完全一样。实际上,语法就是以这种方式定义的,正是为了这个目的(即模块化抽象)。但这是一个完全不同的设计。不仅您继承了
modelUser
,这可能是错误的,而且
modelUser
不再有指向
窗口的指针,这是一个不同的设计,而是消除了原始设计的一些缺陷。假设OP需要某种MVC,M应该对wi一无所知ndows。@juanchopanza删除了一些,但添加了其他。我认为从
modelUser
继承实际上比他已经拥有的更糟糕。@stefaanv感谢这个asnwer。然而,对于完全MVCized的实现,observer更合适。在我当前的项目中,窗口总数不超过10个,只有1个“顶部”窗口和几个“下/从/…”窗口,边界位于