我知道很多其他关于此的文章,但是我迷失了,因为有太多人说前向声明和其他一些令人困惑的事情,我似乎找不到一种方法来避免在编译器中出现新错误,所以如果有人可以帮助我,将不胜感激。

我在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该行已优化_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行之前就未声明Game

查看OptimizedSurface.h包含的 header ,您可能希望它在“Game.h”中声明。现在来看Game.h。它确实有一个Game类的声明。但在此之前,有一个#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,因此不需要它。它只是造成头文件依赖的困惑。

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

除了通过消除不必要的依赖关系来解决它之外,在某些情况下,您还可以通过添加依赖类的“正向声明”来解决循环依赖关系模式(有关更多信息,请参见C++引用)。这对于复杂的依赖关系很重要,但不应该是您这次使用的解决方案。

08-05 06:33