2014-02-06 31 views
0

從Java到C++我試圖通過面向對象理解抽象。瞭解C++中的抽象

爲了說明這個問題,我正在開發一個使用SFML庫進行圖形繪製的小遊戲。然而,這個問題與此無關,只是將其視爲背景信息。無論如何,遊戲的工作方式是通過許多不同的狀態進行處理。在這種情況下2:

  1. 菜單狀態:遊戲的菜單被繪製,遊戲將從這裏開始。

  2. 遊戲狀態:此狀態控制遊戲,將更新實體並繪製它們。

爲了做到這一點,我已經創建了以下類:

GameStateManager.h

#ifndef GAMESTATEMANAGER_H 
#define GAMESTATEMANAGER_H 

#include <SFML/Graphics.hpp> 
#include <iostream> 
#include "GameState.h" 

class GameStateManager 
{ 
public: 
    // Constructor 
    GameStateManager(); 
    // State variables 
    static const int NUMGAMESTATES = 2; 
    static const int MENUSTATE = 0; 
    static const int GAMESTATE = 1; 
    // Public Functions 
    void set_state(int state); 
    void update(); 
    void draw(sf::RenderWindow &win); 
    void input(sf::Event event); 

private: 
    // Array of gamestates 
    GameState game_states[]; 
    // The current state 
    int current_state; 
    // Private functions 
    void load_state(int state); 
    void unload_state(int state); 
}; 

#endif 

GameState.h

#ifndef GAMESTATE_H 
#define GAMESTATE_H 

#include <iostream> 
#include <SFML/Graphics.hpp> 
#include "GameStateManager.h" 

class GameState 
{ 
protected: 
    GameStateManager gsm; 
public: 
    virtual void init() = 0; 
    virtual void update() = 0; 
    virtual void draw(sf::RenderWindow &win) = 0; 
    virtual void input(sf::Event event) = 0; 
}; 

#endif 

現在你可能已經注意到了Array遊戲狀態管理器中的GameStates?這提供了一個我不明白的錯誤:零大小的數組。這是否意味着初始化需要在頭文件中進行?進一步說到這一點,編譯器提到了一個不允許的抽象類數組?

第二個問題是抽象GameState類中的字段gsm無法識別並引發另一個錯誤:缺少類型說明符。

現在讓事情更復雜化,我有以下類:MenuState。這個類是爲了擴展GameState。

MenuState.h

#ifndef MENUSTATE_H 
#define MENUSTATE_H 

#include "GameState.h" 

class MenuState: public GameState 
{ 
public: 
    MenuState(GameStateManager gsm); 
    void init(); 
    void update(); 
    void draw(sf::RenderWindow &win); 
    void input(sf::Event event); 
private: 
    sf::Texture title_texture; 
    sf::Sprite title_sprite; 
}; 

#endif 

如前所述該類將控制遊戲的菜單。如下

GameStateManager.cpp

/* 
* GameState Manager will take care of the various states of the game. 
* In particular there will be two states: Menu or Ingame. GameStateManager 
* will load and unload each state as needed. 
* 
* Author: Ben Euden 
* Date: 2/5/2014 
*/ 

#include "GameStateManager.h" 

// Class Constructor 
GameStateManager::GameStateManager() 
{ 
    game_states = game_states[NUMGAMESTATES]; 

    current_state = MENUSTATE; 
    load_state(current_state); 
} 

/* 
* Load the current game by creating and initialising the state 
* then storing it in the game_states array. 
* @Param state The state we wish to load. 
*/ 
void GameStateManager::load_state(int state) 
{ 
    if(state == MENUSTATE) 
     game_states[state] = MenuState(this); 
    //if(state == GAMESTATE) 
     //game_states[state] = MainGameState(this); // Not implemented yet. 
} 

/* 
* Unload the state we loaded with load_state 
*/ 
void GameStateManager::unload_state(int state) 
{ 
    game_states[state] = NULL; 
} 

void GameStateManager::set_state(int state) 
{ 
    unload_state(state); 
    current_state = state; 
    load_state(state); 
} 

void GameStateManager::update() 
{ 
    try{ 
     game_states[current_state].update(); 
    } 
    catch(int e) 
    { 
     std::cout << "Exception occured during update of game state" << e << std::endl; 
    } 
} 

void GameStateManager::draw(sf::RenderWindow &win) 
{ 
    try{ 
     game_states[current_state].draw(&win); 
    } 
    catch(int e) 
    { 
     std::cout << "Exception occured when trying to draw gamestate: " << current_state << "Exception number: " << e << std::endl; 
    } 
} 

void GameStateManager::input(sf::Event event) 
{ 
    game_states[current_state].input(event); 
} 

而且MenuState:

/* 
* This class extends the Game State header and will deal with the menu of the game 
* this includes drawing the correct text to the screen, moving the selector and 
* either exiting, bringing up about or starting the game. 
* 
* Author: Ben Euden 
* Date: 2/5/2014 
*/ 

#include "MenuState.h" 


MenuState::MenuState(GameStateManager gsm) 
{ 
    gsm = gsm; 
    init(); 

} 

void MenuState::init() 
{ 
    title_texture = sf::Texture(); 
    title_texture.loadFromFile("sprites/Title.png"); 
    title_sprite = sf::Sprite(); 
    title_sprite.setTexture(title_texture); 
    title_sprite.setPosition(512, 200); 
} 

void MenuState::update(){} 

void MenuState::draw(sf::RenderWindow &win) 
{ 
    win.draw(title_sprite); 
} 

void MenuState::input(sf::Event event) 
{ 

} 

請忽略inplemented方法和定位運動用作如下

實施GameStateManager完成。此時我開始嘗試編譯該項目(我使用Visual Studio)出現錯誤時。

現在明白,MainGameState尚未實現,但即使使用MenuState我確信我錯過了一些至關重要的事情,因爲我仍在學習C++。考慮到這一點,請原諒任何破壞公約等,我正在學習,所以隨時糾正我,我更好地學習正確的方式,而不是養成壞習慣。

總結,我想知道爲什麼我收到以下錯誤:

protected: 
    GameStateManager gsm; 

這將產生錯誤:缺少「;」在gsm之前。

GameState game_states[]; 

產生以下錯誤:零大小數組,不允許抽象類數組。

我相信如果我解決了這些問題,其餘的人都會自行解決。

謝謝你的耐心,時間和對此的幫助。

Euden

+0

那麼,你有一對圓形包括,所以這不會幫助... –

+0

如果你可以足夠的指出這些我會很感激它(這可能是一個錯誤,由於編碼延遲到晚上-_-) –

回答

2

要短:你不知道C++中的任何基礎知識,以及作爲一個初學者,你真的應該的形式給出了它作爲一個完全不同的語言比Java或C,所以你應該馬上停止項目並找到一本適合C++初學者的好書。不要試圖混合你的Java知識,只是填補空白,以達到C++知識,它不會工作,因爲即使語法接近,它們是廣泛不同的野獸。

我總是推薦學習C++作爲一種新的和不同的語言,無論你的背景如何。現在你正在犯大錯誤,顯示你在學習C++的錯誤途徑。你應該回到基本的教程(我不想苛刻,你甚至在管理編譯此代碼之前需要學習基礎知識)。

使用數組和成員就好像他們是引用一樣,表明您對「價值語義」以及幾個其他必須知道的C++用法的基本概念缺乏理解。

例如,如果我有

class A 
{ 
    int k = 42; // C++11 
}; 

這裏一個目的將包含A K對象。我的意思是k不是指向int的指針,它是實際值,分配給內存中的

所以,如果我有

A my_object; // object on the stack 

然後my_object是一個對象,以int的大小。所以,如果我做的:

class B 
{ 
    int u; 
    A a; 
}; 

那麼B的一個實例,實際上是一個A對象的大小,再加上一個int的大小。 B對象將所有這些數據包含在單個內存塊中。

所以,當你這樣做:

class GameState 
{ 
    protected: 
    GameStateManager gsm; 

你真正在這裏做的是,你建立一個完整的GameStateManager到任何遊戲狀態對象。 是的,gsm不是一個參考,它是完整的對象。 你應該在這裏做的是使用C++參考(如果遊戲管理員不應該改變)或者使用指針(或者如果涉及所有權的話,使用一個智能poitner)。

我看到很多其他問題,比如你的數組成員進入GameStateManager的含義與Java中的絕對不一樣。基本上,你注意到在C++中編碼。 (並且你應該使用std :: vector或者std :: array,但是你的GameState是動態的,所以它可以是向量或者指針數組 - 甚至是映射或者其他容器)。

由於有太多的時候,我應該得到的核心點:

無論這些都與你以前學過的語言,甚至C或Java,從此再也假設你懂C的任何++但是,你絕對不會。你需要作爲初學者來接近它。將它學習成一門非常新的語言。

並確保您閱讀實際上的好材料the list provided there。很不幸,在線學習關於C++的不良做法非常容易(但它會變得更好)。

此外,您可能需要閱讀此:https://softwareengineering.stackexchange.com/questions/76675/how-can-a-java-programmer-make-the-most-of-a-new-project-in-c-or-c/76695#76695

順便說,相關建議:閱讀"SFML Game Development"書例如簡單和更安全(和C++ - 慣用語)的方法來做到你想做到什麼這裏。

另一方面的建議是avoid using "manager"在你的類型名稱,它只會讓事情很難理解和設計。

0

「零大小的數組」 錯誤是由GameState game_states[];引起的。 在C++中,您必須在聲明時指定數組大小,可以通過具體編寫大小或直接初始化它。

例子:

GameState game_states[ ]; // Error, compiler can't know how much memory to reserve for this. 
GameState game_states[4]; // OK, explicit size given, compiler will reserve enough memory for 4 `GameState` objects. 
GameState game_states[ ] = { GameState(), GameState() }; // OK, direct initialization, compiler will reserve enough memory for 2 `GameState` object. 

你的情況應該是:

GameState game_states[ NUMGAMESTATES ]; 

你應該從GameStateManager構造函數刪除以下行:

game_states = game_states[NUMGAMESTATES]; // Meaningless in C++. 

「抽象類的數組不允許「也出現在這個聲明中,問題是C++不同來自Java的這裏。在C++中,這聲明瞭一個變量,它是一個GameState實例,這是不允許的,因爲GameState具有純虛擬方法,因此無法實例化(就像Java抽象類不能實例化一樣)。爲了在C++中實現這種多態行爲,你必須使用指針或引用,這是Java爲你使用的內容。

修復這應該給你:

GameState * game_states[ NUMGAMESTATES ]; 

「缺少 ';'因爲編譯器無法編譯GameStateManager,因此修復我之前提到的錯誤應該可以解決這個問題。

一些提示:

  • 想想在C++變量從Java int S,即使您已經聲明自己的類型。這意味着它們只是通過聲明來實例化(不需要new),並且在分配給另一個變量時複製它們。 (默認情況下沒有引用語義爲Java)
  • 尋找好的C++書籍/教程,因爲您似乎無法理解C++中的一些非常重要的基本概念。