循环包含

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 TetrisWindowButtonQuit (和一些成员函数)组成。这个 ButtonQuit 再次有一个 TetrisWindow 类型的成员(它有一个 ButtonQuit 类型的成员,它有一个 TetrisWindow 类型的成员 which....)。

这个方案解决不了你的问题,根本不可能成为对方的一员。

您需要的是某种 "knows about" 而不是 "consists of" 关系。

通常这是用指针完成的,所以让你的 ButtonQuit 有一个成员 TetrisWindow* parent 可能是有意义的 - 这是一个非拥有指针,你可以声明你的 TetrisWindow 例如作为具有自动存储持续时间的全局变量(这意味着不需要 delete 它)。

"knows about" 关系的另一个选项是引用,但需要在构造函数中设置引用 - 这意味着您需要在 ButtonQuitButtonQuitTetrisWindow.

之前