预期 C++ 错误 class-名称在“{”标记之前

C++ error expected class-name before '{' token

我知道很多很多人已经发布了关于这个的帖子,但我很迷茫,因为有这么多人说前瞻性声明和其他非常混乱的事情,我似乎无法找到一种方法来使用而不提出新的我的编译器中的错误,所以如果有人能帮助我,我将不胜感激。

我在 Ubuntu 15.04

上使用 Code::Blocks

错误是OptimizedSurface.h|11|error: expected class-name before ‘{’ token

在 OptimizedSurface Header 文件中我决定做 class OptimizedSurface : Game{ 因为在这个错误之前我得到

include/Game.h|18|error: invalid use of member ‘Game::windowSurface’ in static member function 线是 optimized_surface = SDL_ConvertSurface(surface, Game::windowSurface->format, 0);

现在代码是下面的文件。

main.cpp -

#include "Game.h"
#include <stdio.h>


int main(int argc, char* args[]){
    printf("Initializing Game class\n");
    Game game = Game();
    return 0;
}

Game.h -

#ifndef GAME_H
#define GAME_H

#include "SDL2/SDL.h"
#include "SDL2/SDL_image.h"
#include <stdio.h>
#include <chrono>
#include <thread>
#include <iostream>
#include "MenuState.h"

class MenuState;

class Game{
    public:
        Game();
        virtual ~Game();
        SDL_Surface *windowSurface = nullptr;

    protected:

    private:
        void tick();
        void update_time();
        std::chrono::system_clock::time_point now, last_frame;
        int delta = 0;
        void event_handler();
        void render();

        // Screen Dimensions
        const int SCREEN_WIDTH = 640;
        const int SCREEN_HEIGHT = 480;

        //Main Window
        SDL_Window *window = nullptr;

        // Surfaces
        SDL_Surface *currentImage = nullptr;

        // Main Menu Screen
        MenuState *menu;

        bool isRunning = true;

        // Main Menu = 1; Game = 2; Paused = 3;
        int currentState = 1;

        // Events
        SDL_Event ev;
};

#endif // GAME_H

Game.cpp -

#include "Game.h"


Game::Game(){
    // Initialize SDL
    if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
        printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() );

    else{
        this->menu = new MenuState;
        // Create Window
        this->window = SDL_CreateWindow( "Tetris", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN );

        if( this->window == NULL ){
            printf( "Window could not be created! SDL_Error: %s\n", SDL_GetError() );
        }

        else{
            // Get window surface
            this->windowSurface = SDL_GetWindowSurface( this->window );

            // Fill the surface white
            SDL_FillRect( this->windowSurface, NULL, SDL_MapRGB( this->windowSurface->format, 0xFF, 0xFF, 0xFF ) );

            // Update the Surface
            SDL_UpdateWindowSurface( this->window );

            //Set current image to display as main menu
            this->currentImage = this->menu->MenuSurface[ 0 ];
            this->tick();
        }
    }
}

void Game::tick(){
    while( this->isRunning ){
        if( !( this->delta >= 33 ) )
            this->update_time();
        else{
            this->last_frame = std::chrono::system_clock::now();
            this->event_handler();
            this->render();
        }
    }
}

void Game::update_time(){
    this->now = std::chrono::system_clock::now();
    this->delta = std::chrono::duration_cast<std::chrono::milliseconds>(this->now - this->last_frame).count();
}

void Game::event_handler(){
    while( SDL_PollEvent( &this->ev ) != 0 && this->currentState == 1){
        switch( this->ev.type ){
            case SDL_MOUSEBUTTONDOWN:
                if( this->ev.button.button  == SDL_BUTTON_LEFT )
                    if( this->menu->checkPos( this->ev.button.x, this->ev.button.y ) )
                        this->currentImage = this->menu->MenuSurface[ 2 ];
                    break;

            case SDL_MOUSEBUTTONUP:
                if( this->ev.button.button == SDL_BUTTON_LEFT )
                    if( this->menu->checkPos( this->ev.button.x, this->ev.button.y ) )
                        currentState = 2;
                        // Start the Game
            default:
                if( this->menu->checkPos( this->ev.button.x, this->ev.button.y ) )
                    this->currentImage = this->menu->MenuSurface[ 1 ];
                else
                    this->currentImage = this->menu->MenuSurface[ 0 ];
                break;
        }
    }
    if( this->ev.type == SDL_QUIT )
        this->isRunning = false;
}

void Game::render(){
    SDL_BlitSurface( this->currentImage, NULL, windowSurface, NULL );
    SDL_UpdateWindowSurface( window );
}

Game::~Game(){
    // Destroy Everything
    this->currentImage = nullptr;

    SDL_DestroyWindow( this->window );
    this->window = nullptr;

    delete menu;

    // Quit SDL subsystems
    SDL_Quit();
}

MenuState.h -

#ifndef MENUSTATE_H
#define MENUSTATE_H

#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include "OptimizedSurface.h"
#include <string>


class MenuState{
    public:
        MenuState();
        virtual ~MenuState();

        bool checkPos( int x, int y );

        SDL_Surface *MenuSurface[ 3 ];

        int buttonX [ 2 ];
        int buttonY [ 2 ];

    protected:

    private:
};

#endif // MENUSTATE_H

MenuState.cpp -

#include "MenuState.h"


MenuState::MenuState(){
    for( int i = 1; i <= 3; ++i){
        this->MenuSurface[ i-1 ] = OptimizedSurface::convert( "assets/menu/" + std::to_string(i) + ".jpg" );
    }
    this->buttonX[ 0 ] = 250;
    this->buttonX[ 1 ] = buttonX[ 0 ] + 140;

    this->buttonY[ 0 ] = 36;
    this->buttonY[ 1 ] = buttonY[ 0 ] + 100;
}

bool MenuState::checkPos( int x, int y ){
    if( this->buttonX[ 0 ] < x && x < this->buttonX[ 1 ] )
        if( this->buttonY[ 0 ] < y && y < this->buttonY[ 1 ] )
            return true;
    return false;
}

MenuState::~MenuState(){
    for( int i = 0; i < 3; ++i ){
        SDL_FreeSurface( this->MenuSurface[ i ] );
        this->MenuSurface[ i ] = nullptr;
    }
}

OptimizedSurface.h -

#ifndef OPTIMIZEDSURFACE_H
#define OPTIMIZEDSURFACE_H

#include "SDL2/SDL.h"
#include "SDL2/SDL_image.h"
#include "Game.h"
#include <iostream>
#include <stdio.h>


class OptimizedSurface : public Game{
    public:
        OptimizedSurface();
        static SDL_Surface *convert( std::string filepath );
        virtual ~OptimizedSurface();
    protected:
    private:
};

#endif // OPTIMIZEDSURFACE_H

OptimizedSurface.cpp -

#include "OptimizedSurface.h"


OptimizedSurface::OptimizedSurface(){
}

SDL_Surface *OptimizedSurface::convert( std::string filepath ){
    SDL_Surface *optimized_surface = nullptr;
    SDL_Surface *surface = IMG_Load(filepath.c_str());
    if( surface == NULL ){
        printf( "Error Optimizing Surface: %s\n", SDL_GetError() );
    }
    else{
        optimized_surface = SDL_ConvertSurface(surface, windowSurface->format, 0);
        if( optimized_surface == NULL )
            printf( "Error Optimizing Surface: %s\n", SDL_GetError() );
    }
    SDL_FreeSurface(surface);

    return optimized_surface;
}

OptimizedSurface::~OptimizedSurface(){
}

如果您按照错误消息进行操作,它说: OptimizedSurface.h|11|error: expected class-name before ‘{’ token

看看 OptimizedSurface.h,第 11 行。你有: class OptimizedSurface : public Game{

这没什么问题,但错误是无法识别“{”之前的标识符。该标识符是 Game。因此,出于某种原因,在到达第 11 行之前未声明 [​​=12=]。

查看 OptimizedSurface.h 包含的 header,您可能希望它在 "Game.h" 中声明。所以现在看看Game.h。它确实有 Game class 的声明。但是之前,还有一个#include "MenuState.h"。你应该猜到这是干扰。

在 MenuState.h 中,您有 #include "OptimizedSurface.h"...

明白了吗?这是一个循环#include 模式。您的 OptimizedSurface 需要了解 Game,但 Game.h 正试图先声明 OptimizedSurface(通过 MenuState.h)! OptimizedSurface.h 依赖于 Game.h,Game.h 依赖于 MenuState.h,MenuState.h 依赖于 OptimizedSurface.h.

最好的解决办法是从 MenuState.h 中删除 #include "OptimizedSurface.h"。 MenuState 实际上并不依赖于 OptimizedSurface,因此不需要它。它只是造成了 header 依赖关系的混乱。

如果您确实有一个 实现 依赖项,那么您应该在 cpp 文件中 #include 适当的 header。您提到 MenuState.cpp 依赖于 OptimizedSurface,因此将 #include "OptimizedSurface.h" 添加到 MenuState.cpp 而不是 MenuState.h.

除了通过删除不必要的依赖来修复它之外,在某些情况下,您还可以通过添加 "forward declaration" 依赖 class 来解决循环依赖模式(有关更多信息,请参见良好的 C++ 参考)。这对于复杂的依赖关系很重要,但不应该是你这次使用的解决方案。