相互依赖的类和继承

Mutually dependent classes and inheritance

本文关键字:继承 依赖      更新时间:2023-10-16

我正在研究一个小C++WinAPI包装器。我想创建自己的窗口并将自己的控件附加到其中。 我创建了2个类:窗口和控件。 问题是我很难处理多个头文件,因为类控件需要类窗口,反之亦然。当我编译我的代码时,我收到很多错误。

这是我的文件:

全局.h :

// globals.h
// I need this file to define a few constants and to include the main headers needed by my classes
#ifndef GLOBALS_H
#define GLOBALS_H
#include <windows.h>
#include <iostream>
#include <vector>
#include "window.h"
#define SOME_GLOBAL_CONSTANT    1
#endif

窗口.h :

// window.h
#ifndef WINDOW_H
#define WINDOW_H
#include "globals.h"
#include "control.h"
class Window
{
public:
Window(RECT windowRect);
virtual ~Window();
void appendChild(Control* child);
private:
RECT m_windowRect;
Control m_staticBackground;
std::vector<Control*> m_children;
};
#endif

窗口.cpp :

// window.cpp
#include "window.h"
Window::Window(RECT windowRect) : m_windowRect(windowRect)
{
std::cout << SOME_GLOBAL_CONSTANT << std::endl;
}
Window::~Window()
{
m_children.clear();
}
void Window::appendChild(Control* child)
{
m_children.push_back(child);
}

控制.h :

// control.h
#ifndef CONTROL_H
#define CONTROL_H
#include "globals.h"
class Control
{
public:
Control(Window* parentWindow);
virtual ~Control();
private:
RECT m_controlRect;
Window* m_parentWindow;
};
#endif

控制.cpp :

// control.cpp
#include "control.h"
Control::Control(Window* parentWindow) : m_controlRect({}), m_parentWindow(parentWindow)
{
std::cout << SOME_GLOBAL_CONSTANT << std::endl;
}
Control::~Control()
{}

最后,主要.cpp:

#include "globals.h"

class MyCustomControl : public Control
{
public:
MyCustomControl(Window* parentWindow) : Control(parentWindow)
{}
~MyCustomControl()
{}
};
class MyWindow : public Window
{
public:
MyWindow(RECT windowRect) : Window(windowRect)
{
kid1 = new MyCustomControl(this);
appendChild(kid1);
}
~MyWindow()
{
delete kid1;
}
private:
MyCustomControl* kid1;
};
int main()
{
MyWindow appWindow;
std::cout << SOME_GLOBAL_CONSTANT << std::endl;
return 0;
}

以下是我得到的所有编译错误:

1>------ Build started: Project: include, Configuration: Debug Win32 ------
1>window.cpp
1>d:visual studio 2017projectsincludeincludecontrol.h(9): error C2061: syntax error: identifier 'Window'
1>d:visual studio 2017projectsincludeincludecontrol.h(14): error C2143: syntax error: missing ';' before '*'
1>d:visual studio 2017projectsincludeincludecontrol.h(14): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>d:visual studio 2017projectsincludeincludecontrol.h(14): error C2238: unexpected token(s) preceding ';'
1>main.cpp
1>d:visual studio 2017projectsincludeincludecontrol.h(9): error C2061: syntax error: identifier 'Window'
1>d:visual studio 2017projectsincludeincludecontrol.h(14): error C2143: syntax error: missing ';' before '*'
1>d:visual studio 2017projectsincludeincludecontrol.h(14): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>d:visual studio 2017projectsincludeincludecontrol.h(14): error C2238: unexpected token(s) preceding ';'
1>d:visual studio 2017projectsincludeincludemain.cpp(8): error C2664: 'Control::Control(const Control &)': cannot convert argument 1 from 'Window *' to 'const Control &'
1>d:visual studio 2017projectsincludeincludemain.cpp(8): note: Reason: cannot convert from 'Window *' to 'const Control'
1>d:visual studio 2017projectsincludeincludemain.cpp(8): note: No constructor could take the source type, or constructor overload resolution was ambiguous
1>d:visual studio 2017projectsincludeincludemain.cpp(32): error C2512: 'MyWindow': no appropriate default constructor available
1>d:visual studio 2017projectsincludeincludemain.cpp(13): note: see declaration of 'MyWindow'
1>control.cpp
1>d:visual studio 2017projectsincludeincludewindow.h(13): error C2061: syntax error: identifier 'Control'
1>d:visual studio 2017projectsincludeincludewindow.h(17): error C3646: 'm_staticBackground': unknown override specifier
1>d:visual studio 2017projectsincludeincludewindow.h(17): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>d:visual studio 2017projectsincludeincludewindow.h(18): error C2065: 'Control': undeclared identifier
1>d:visual studio 2017projectsincludeincludewindow.h(18): error C2059: syntax error: '>'
1>d:visual studio 2017projectsincludeincludewindow.h(18): error C2976: 'std::vector': too few template arguments
1>c:program files (x86)microsoft visual studio2017communityvctoolsmsvc14.10.25017includevector(700): note: see declaration of 'std::vector'
1>Generating Code...
1>Done building project "include.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

任何帮助将不胜感激。

提前谢谢你,

Winapiwrapper。

编辑:我也阅读了这个线程,但我无法解决我的问题。

欢迎来到编程。删除一条错误消息,两条错误消息将取而代之。

井。。。没有。正在发生的事情是,当您解决一个错误时,这揭示了珍贵错误隐藏的错误。

首先是公益广告:

不要在没有编译和测试的情况下编写太多代码。这样,当出现问题时,您需要检查的代码量更少。从main函数开始。确保它构建。添加所需的标头。确保它构建。编写一个函数供main调用。确保它构建。重复直到程序完成。尝试一次添加太多会导致一连串的错误风暴,就像您在这里遇到的那样。

全局包含头文件通常是一个傻瓜。它们经常导致您遇到诸如此处的循环依赖关系之类的问题,并使文件包含所有内容,即使它们不必包含。这可能会减慢构建时间。

接下来,在继续之前阅读以下链接:解析标头包含循环依赖项

现在回答:

window.h 包括 control.h. control .h包括 window.h 虽然 global.h.这导致了上面链接中讨论的鸡和蛋问题。其中一个标头将包含在另一个标头之前,并且无法找到另一个文件的内容。幸运的是,control.h 只需要对Window的引用,而不是整个事情,这可以通过前向声明和删除全局包含文件来满足。

我不会演示清理它。该过程在链接中详细记录。

这暴露了 hydra 头号 2:Window包含Control m_staticBackground并且没有显式初始化它。这导致编译器四处寻找默认构造函数Control,这是不存在的。

解决方案:显式初始化m_staticBackground

Window::Window(RECT windowRect) : m_windowRect(windowRect),
m_staticBackground(this)
{
std::cout << SOME_GLOBAL_CONSTANT << std::endl;
}

大妈妈在这里吓坏了:m_staticBackground(this)狡猾得要命。this还没有完全构建,所以如果你做的不仅仅是把它存储在Control::Control(这就是你目前正在做的全部),就会发生非常糟糕、不可预测的事情。请勿使用parentWindowm_parentWindowControl构造函数的主体内部。如果可能的话,找到一种更好、更安全的方法。如果不可能,请用"请勿使用"消息记录它,以提醒您未来的自己或其他查看代码的人不要使用它们。

修复此问题后,您可以

MyWindow appWindow;

main.MyWindow的构造函数需要一个您当前没有RECT提供的RECT,所以我就到此为止。

"window.h"globals.h移动到controls.cpp。并把class Window;放在class Controls {之前controls.h.这称为前向声明。

您甚至不需要controls.cpp中的window.h,您可以将其直接移动到您的main.cpp