【问题标题】:Incomplete type, but I'm using forward declarations?不完整的类型,但我正在使用前向声明?
【发布时间】:2018-03-18 21:30:34
【问题描述】:

我在做什么: 我有两个文件:game.h 和 sound_controller.h。他们俩都在互相冲突。 game.h 需要有 SoundController,而 sound_controller.h 需要有 Game,所以它们都包含彼此的头文件。

问题: game.h 第 26 行:

error: field soundController has incomplete type 'SoundController'

我在 game.h 中包含了 sound_controller.h,但它表示类型不完整,但我已经声明了 SoundController 类。那么我该如何解决呢?

代码:

游戏.h:

#pragma once

/**
    game.h
    Handles highest level game logic
*/

#include <SDL.h>
#include <SDL_image.h>
#include <SDL_ttf.h>
#include <SDL_mixer.h>

#include <iostream>

#include "config.h"
#include "sound_controller.h"
#include "image_controller.h"

#include <stdarg.h>

class SoundController; //forward declaration

class Game {

    ImageController imageController;
    SoundController soundController;

    SDL_Window* window = NULL;

    bool running;


public:
    Game();
    bool init();
    bool createWindow();

    void update();

    static void log(const char* format, ...);

};

sound_controller.h:

#pragma once

/**
    sound_controller.h
    Allows for manipulation with sound (sound effects and music)
*/

#include "config.h"
#include <SDL_mixer.h>
#include "Game.h"

class Game; //forward declaration

class SoundController {

    bool init();
    bool load_sound();
    bool load_music();

    void music_play();
    void music_pause();
    void music_stop();

};

sound_controller.cpp 使用 Game 是因为它调用 Game.h 的静态函数:log。

编辑:

从 sound_controller.h 中删除了“#include game.h”。这次在 sound_controller.cpp 中又出现了一个错误:

line 8 error: incomplete type 'Game' used in nested name specifier

sound_controller.cpp:

#include "sound_controller.h"

bool SoundController::init() {
    bool success = true;

    //Initialize SDL_mixer
    if( Mix_OpenAudio( 44100, MIX_DEFAULT_FORMAT, 2, 2048 ) < 0 ) {
        Game::log( "SDL_mixer could not initialize! SDL_mixer Error: %s\n", Mix_GetError() );
        success = false;
    }

    return success;

}

EDIT2:

解决方案是将#include "game.h" 放入 sound_controller.cpp。

【问题讨论】:

标签: c++ forward-declaration incomplete-type


【解决方案1】:

你有一个循环依赖——你的每个头文件都试图#include另一个;但是你不能同时拥有它:两个头文件中的一个将首先被解析,当解析器解析第一个头文件时,它(还)不知道第二个头文件的内容(这就是它抱怨的原因“不完整的类型”)。

在这种情况下,简单的解决方法是从 sound_controller.h 文件中删除“#include Game.h”行。

【讨论】:

  • 所以我删除了#include game.h,但现在sound_controller.cpp 中出现了另一个错误,我在第一篇文章中包含了上面的代码以及错误。
  • 您需要将“#include Game.h”添加到您的 sound_controller.cpp 文件中。
【解决方案2】:

对我来说,你似乎还是迷路了。让我们简化测试用例:

class A {
public:
    A();
    B b;
};

class B {
public:
    B();
    A a;
};

A::A() {;}
B::B() {;}

当编译器计算出 A 时,编译器必须知道其字段 b 的类型 B。A 的 b 是成员数据,其内存将在 A 实例化时分配。要知道它,编译器需要这个:

class B {
public:
    B();
    A a;
};

同样,为了让编译器弄清楚应该如何为B的a分配内存,编译器应该知道A。因此,它是一个循环依赖,无法解决。

幸运的是,您的 SoundController 没有 Game,而 Game 有 SoundController。因此,没有循环依赖。只有那个 class SoundController { ... } 应该在 class Game { ... } 之前。

但是,在我的示例中,如果 A 和 B 相互依赖,或者在多个类之间存在循环依赖,这将是一个问题。

为了解决这个问题,如果字段的类型是类,前向声明本身没有帮助。换句话说,如果在实例化类本身时应该为字段分配和布局一些内存,则前向声明无济于事。只有当字段的类型是指针或对其他类的引用时,它才有帮助。在我的示例中,前向声明仅在 A 的字段 b 为 B* 或 B& 时才有效。

class A {
public:
    A();
    B* b; // whatever the pointer points to, the size of the pointer is given
};

class B {
public:
    B();
    A a; // the compiler now can fine A from above
};

现在,编译器知道它将为 A 分配多少内存以及内存布局是什么。在那里,编译器不必知道 B 的大小。它只需要知道指针的大小。由于A的内存布局解决了,编译器就可以解决下面B的内存布局等问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-09
    • 2012-06-28
    • 2014-02-02
    • 1970-01-01
    相关资源
    最近更新 更多