循环包含
CIrcular Inclusion
我正在构建俄罗斯方块,并试图避免指针。在下面的代码中,我试图在另一个 class "TetrisWindow" 中定义一个 class "ButtonQuit" 的实例,两个 class 都使用彼此的方法。我不断收到错误消息:
‘ButtonQuit’ does not name a type: ButtonQuit btnQuit;
或:
field ‘btnQuit’ has incomplete type: ButtonQuit btnQuit;
我知道有一个循环包含,但我不知道如何解决这个问题。我试过向前声明 ButtonQuit,它不起作用。
(WindowSDL只是一个包含所有图形功能的class,除了SDL,它没有包含在其中。)
这是我的代码(编译时出现 "does not name a type" 错误):
BUTTONQUIT.HPP:
#ifndef __BUTTONQUIT__
#define __BUTTONQUIT__
#include <TetrisWindow.hpp>
class ButtonQuit{
private:
int x,y;
TetrisWindow win;
public:
ButtonQuit (TetrisWindow, int, int);
~ButtonQuit();
void print(void);
void action(void);
bool clicked(int, int);
};
#endif
TETRISWINDOW.HPP:
#ifndef __TETRISWINDOW__
#define __TETRISWINDOW__
#include <cstdint>
#include <string>
#include <vector>
#include <WindowSDL.hpp>
#include <ButtonQuit.hpp>
class TetrisWindow: public WindowSDL{
protected:
ButtonQuit btnQuit;
void handleEvent(SDL_Event&);
void work(void);
public:
TetrisWindow();
TetrisWindow(uint16_t, uint16_t);
TetrisWindow(const TetrisWindow& w);
~TetrisWindow();
void drawWindow(void);
};
#endif
问题不在于您的情况中的循环包含,这是次要问题。
您应该考虑的第一个问题是 TetrisWindow
有一个 ButtonQuit
成员,而 ButtonQuit
有一个 TetrisWindow
成员。
这两个成员既不是指针也不是引用,这意味着它们将以整个大小存储在包含 class 中。这导致了一个没有结束的递归结构。
TetrisWindow
必须包含一个 ButtonQuit
,其中必须包含一个 TetrisWindow
,而 TetrisWindow
必须包含一个 ButtonQuit
...
这里的解决方案是在各自的其他 headers 中转发声明两个 classes 并使用 pointers/references 代替,例如:
// TetrisWindow.h
class ButtonQuit;
class TetrisWindow {
private:
ButtonQuit* button;
...
}
// ButtonQuit.h
class TetrisWindow;
class ButtonQuit {
private:
TetrisWindow* window;
...
}
现在您使用指针作为成员,因此编译器不必知道 sizeof(ButtonQuit)
或 sizeof(TetrisWindow)
的定义,因为指针始终是指针。这允许您根本不包含另一个 class 的 headers,只要您没有试图访问不完整类型的内联函数。
您的 class TetrisWindow
由 ButtonQuit
(和一些成员函数)组成。这个 ButtonQuit
再次有一个 TetrisWindow
类型的成员(它有一个 ButtonQuit
类型的成员,它有一个 TetrisWindow
类型的成员 which....)。
这个方案解决不了你的问题,根本不可能成为对方的一员。
您需要的是某种 "knows about" 而不是 "consists of" 关系。
通常这是用指针完成的,所以让你的 ButtonQuit
有一个成员 TetrisWindow* parent
可能是有意义的 - 这是一个非拥有指针,你可以声明你的 TetrisWindow
例如作为具有自动存储持续时间的全局变量(这意味着不需要 delete
它)。
"knows about" 关系的另一个选项是引用,但需要在构造函数中设置引用 - 这意味着您需要在 ButtonQuit
和 ButtonQuit
在 TetrisWindow
.
之前
我正在构建俄罗斯方块,并试图避免指针。在下面的代码中,我试图在另一个 class "TetrisWindow" 中定义一个 class "ButtonQuit" 的实例,两个 class 都使用彼此的方法。我不断收到错误消息:
‘ButtonQuit’ does not name a type: ButtonQuit btnQuit;
或:
field ‘btnQuit’ has incomplete type: ButtonQuit btnQuit;
我知道有一个循环包含,但我不知道如何解决这个问题。我试过向前声明 ButtonQuit,它不起作用。
(WindowSDL只是一个包含所有图形功能的class,除了SDL,它没有包含在其中。)
这是我的代码(编译时出现 "does not name a type" 错误):
BUTTONQUIT.HPP:
#ifndef __BUTTONQUIT__
#define __BUTTONQUIT__
#include <TetrisWindow.hpp>
class ButtonQuit{
private:
int x,y;
TetrisWindow win;
public:
ButtonQuit (TetrisWindow, int, int);
~ButtonQuit();
void print(void);
void action(void);
bool clicked(int, int);
};
#endif
TETRISWINDOW.HPP:
#ifndef __TETRISWINDOW__
#define __TETRISWINDOW__
#include <cstdint>
#include <string>
#include <vector>
#include <WindowSDL.hpp>
#include <ButtonQuit.hpp>
class TetrisWindow: public WindowSDL{
protected:
ButtonQuit btnQuit;
void handleEvent(SDL_Event&);
void work(void);
public:
TetrisWindow();
TetrisWindow(uint16_t, uint16_t);
TetrisWindow(const TetrisWindow& w);
~TetrisWindow();
void drawWindow(void);
};
#endif
问题不在于您的情况中的循环包含,这是次要问题。
您应该考虑的第一个问题是 TetrisWindow
有一个 ButtonQuit
成员,而 ButtonQuit
有一个 TetrisWindow
成员。
这两个成员既不是指针也不是引用,这意味着它们将以整个大小存储在包含 class 中。这导致了一个没有结束的递归结构。
TetrisWindow
必须包含一个 ButtonQuit
,其中必须包含一个 TetrisWindow
,而 TetrisWindow
必须包含一个 ButtonQuit
...
这里的解决方案是在各自的其他 headers 中转发声明两个 classes 并使用 pointers/references 代替,例如:
// TetrisWindow.h
class ButtonQuit;
class TetrisWindow {
private:
ButtonQuit* button;
...
}
// ButtonQuit.h
class TetrisWindow;
class ButtonQuit {
private:
TetrisWindow* window;
...
}
现在您使用指针作为成员,因此编译器不必知道 sizeof(ButtonQuit)
或 sizeof(TetrisWindow)
的定义,因为指针始终是指针。这允许您根本不包含另一个 class 的 headers,只要您没有试图访问不完整类型的内联函数。
您的 class TetrisWindow
由 ButtonQuit
(和一些成员函数)组成。这个 ButtonQuit
再次有一个 TetrisWindow
类型的成员(它有一个 ButtonQuit
类型的成员,它有一个 TetrisWindow
类型的成员 which....)。
这个方案解决不了你的问题,根本不可能成为对方的一员。
您需要的是某种 "knows about" 而不是 "consists of" 关系。
通常这是用指针完成的,所以让你的 ButtonQuit
有一个成员 TetrisWindow* parent
可能是有意义的 - 这是一个非拥有指针,你可以声明你的 TetrisWindow
例如作为具有自动存储持续时间的全局变量(这意味着不需要 delete
它)。
"knows about" 关系的另一个选项是引用,但需要在构造函数中设置引用 - 这意味着您需要在 ButtonQuit
和 ButtonQuit
在 TetrisWindow
.