2017-04-02 45 views
-1

我一直在編程的冒險遊戲,並擁有一切整個二維數組地牢工作,直到運動。地圖是他們自己的結構,而角色是一個類。 Character類的成員變量之一是Map,curMap,它表示玩家當前所在的地圖。但是,在Main.cpp中進行測試時,作品和地圖沒有正確更新。這是代碼,之後我會解釋我已經完成了什麼。C++ - 類不更新成員正確

Maps.h

#include <string> 
#include <vector> 

using namespace std; 

struct Map { 
    vector<string> layout; 
    vector<int> exits; //indices in allMaps array 
    string name; 
    int level; 
    Map(); 
    Map(vector<string> l, vector<int> e, string n, int lvl); 

}; 

extern Map noMap; 
extern Map highashPlainsA, highashPlainsB, highashPlainsC; //Highash Plains 
extern Map alnwick, alnwickForge, alnwickMarket, alnwickInn; //Alnwick 
extern vector<Map> allMaps; 

extern vector<string> blankLayout; 
extern vector<string> plainsLayoutA, plainsLayoutB, plainsLayoutC; //Highash Plains 
extern vector<string> alnwickLayout; //Major Towns 
extern vector<string> forgeLayout, marketLayout, innLayout; //Town Buildings 

Maps.cpp

#include "Maps.h" 

Map::Map() : 
    layout(blankLayout), 
    exits({0, 0, 0, 0}), 
    name("_NO_MAP_"), 
    level(0){} 

Map::Map(vector<string> l, vector<int> e, string n, int lvl) : 
    layout(l), 
    exits(e), 
    name(n), 
    level(lvl){} 

Map noMap = Map(); 
Map highashPlainsA = Map(plainsLayoutA, {4, 3, 2}, "Highash Plains A", 1); 
vector<Map> allMaps = {noMap, highashPlainsA}; 

vector<string> blankLayout = 
{"##############################", 
"#       #", 
"#       #", 
"#       #", 
"#       #", 
"#       #", 
"#       #", 
"#       #", 
"#       #", 
"##############################"}; 

vector<string> plainsLayoutA = 
{"##########################33##", 
"# G ##### ####### E #### 2", 
"# # # D # # G  #  2", 
"# # # ## ####################", 
"# # ##E# # G   G#", 
"#E# G# G     G#", 
"# # ##########E############", 
"# #### #DE G    ED#", 
"# ###D #DE   G  ED#", 
"################111###########"}; 

Character.h(我切出了很多不重要的代碼在這裏)

#include "Maps.h" 
#include <iostream> 

class Character { 

Map curMap; 

public:  
    Character(); 
    ~Character(); 
    void SetMap(Map map); 
    Map GetMap(); 
}; 

extern Character player; 

Character.cpp(左明表示不重要的代碼在這裏也一樣)

#include "Character.h" 

Character::Character() : curMap(highashPlainsA){} 

Character::~Character(){} 

void Character::SetMap(Map map){ 
    cout << "OLD MAP NAME: " << curMap.name << "\n"; 
    curMap = map; 
    curMap.layout = map.layout; 
    curMap.exits = map.exits; 
    curMap.name = map.name; 
    curMap.level = map.level; 
    cout << "NEW MAP NAME: " << curMap.name << "\n"; 
} 

Map Character::GetMap(){ 
    return curMap; 
} 

Character player = Character(); 

Main.cpp的

#include "Character.h" 

int main(){ 
    player.SetMap(highashPlainsA); 
    cout << "\nSIZE OF CURRENT LAYOUT: " << player.GetMap().layout.size() << "\n"; 
    cout << "SIZE OF PLAINS A: " << plainsLayoutA.size() << "\n"; 
    cout << "Name of map: " << player.GetMap().name << "\n"; 
// cout << "Layout of map: \n" << player.GetMap().layout[0] << "\n" << player.GetMap().layout[1] << "\n" << player.GetMap().layout[2] << "\n"<< player.GetMap().layout[3] << "\n"; // Crashes because for whatever reason the layout size is 0 
    return 0; 
} 

什麼已經過測試:Character::SetMap()我甚至嘗試改變各個體變量,但不應該將Map設置爲整體來更改所有這些值?此外,在Map::Map(vector<string> l, vector<int> e, string n, int lvl),我試過它沒有初始化列表,但它仍然無法正常工作。我並沒有真正期待它,但我猜這值得一試。

的問題:

控制檯輸出:

OLD MAP NAME: Highash Plains A 
NEW MAP NAME: Highash Plains A 

SIZE OF CURRENT LAYOUT: 0 
SIZE OF PLAINS A: 10 
Name of map: Highash Plains A 

的字符類確實初始化curMap成員,並調用默認的構造函數這樣做。這是預期的功能,因爲在安裝過程中播放器所處的地圖無關緊要。然而,在嘗試設置映射到另一個預先創建地圖實例(使用SetMap(),一切都從那裏順心。按照控制檯記錄,的curMap名稱設置爲正確的名稱(OLD地圖名稱),並保持這一套時。新的地圖可是,佈局而日誌的目標載體的直接尺寸給出了正確的值返回一個空向量到底是怎麼回事,我怎麼能解決這個問題

+3

歡迎計算器.COM。請花些時間閱讀[幫助頁面](http://stackoverflow.com/help),尤其是名爲[「我可以問些什麼話題?」](http://stackoverflow.com/help/討論話題)和[「我應該避免問什麼類型的問題?」](http://stackoverflow.com/help/dont-ask)。也請[tour](http:// stackoverflow。com/tour)並閱讀[如何提出好問題](http://stackoverflow.com/help/how-to-ask)。最後,請學習如何創建[最小,完整和可驗證示例](http://stackoverflow.com/help/mcve)。 – Weaboo

+0

雖然您提供了很多信息,但您並未給出一個最小完整的可驗證示例。此代碼不能編譯,所以我們不能簡單地重現您的問題。 – JHBonarius

+1

目前還不清楚你的實際問題是什麼,因爲有很多不重要的信息,沒有足夠的重要信息。哪種方法不符合您的預期? 'SetMap'? – jwimberley

回答

0

解決:你的問題是對於HighplainsA構造正在構造函數用於plainsLayout之前調用,這是因爲所有構造函數是在全球範圍內,所以他們正在運行的順序是下降到純粹的運氣。這就是爲什麼在全球範圍內具有靜態變量的例子只是一般一個可怕的想法。

當我將調試語句放入Map的構造函數時,佈局數據爲空。這是因爲佈局數據自己的構造函數尚未執行,它是一個空向量。但是,一旦你點擊了main,所有的構造函數都已經運行,所以看起來佈局是正確的。創建地圖時,這是不正確的。

請注意,如果您嘗試做正確的事情並將字符串的原始const char * []表更改爲向量變量,則這是一個可能遇到的隱患。原始char *表沒有構造函數,它是在編譯時確定的一些內存地址,而矢量在它們有效之前必須調用構造函數。解決該問題的一種方法是將參考存儲到Map中的佈局矢量,而不是將其複製。這樣,當你實際訪問它的時候,所有的數據都將被構建,並且全局值僅僅是連接點。

但是,根本不要依賴全局變量,因爲任何時候當你給出一個具有構造函數的類類型時,就必須在程序開始時調用它。如果您使用另一個對象,如具有的構造函數(例如您的矢量佈局),並且您在構造函數中將其用於另一個也位於全局範圍內的對象,則這一點尤其糟糕。任何人都會猜測哪一個會先運行。

基本上,您想爲所有依賴其他數據的數據創建初始化函數。然後,您可以手動控制數據初始化的順序。

~~~

一些其他的建議是當你進入地圖,以儘量減少你所創建的地圖的副本數量:

Map &Character::GetMap(){ 
    return curMap; 
} 

^這個返回到實際地圖參考。每次這個被調用之前,你都在製作另一個副本,然後在完成使用時複製被刪除。

至於存儲地圖。目前,Character還有拷貝的地圖。這與您的地圖對象不在字符中不一樣。我不知道這是否是由設計,但你可能不打算。地圖需要被許多類使用,例如敵人,以及角色。所以每個角色都不應該有地圖的完整副本。

引用可以存儲在類中,但只有當對象被創建時,所以如果您使用引用來存儲地圖,則創建角色後無法更改。然而,指針與引用類似,但可以在運行時進行更改。例如你可以這樣做:

class Character 
{ 
    Map *currMap; // * here specifies that it is a pointer 

    void setMap(Map &newMap) // & here specifies that it is a reference 
    { 
     currMap = &newMap; // & here, turns a reference into a pointer 
    } 


    Map &Character::GetMap() // & here, is returning a reference 
    { 
     return *curMap; // * here, turns a pointer into a reference 
    } 
} 

指針* currmap擁有地圖的地址。一個引用&的newMap被傳入,然後內存地址(& newMap)被保存在currMap中。不要對*和&感到困惑,它們在這裏使用的環境稍有不同,所以你只需要記住哪個場合。爲了從一個指針訪問子值,你可以做到這一點通過下列方式之一:

currMap->name; // get a subvalue from a pointer 

(*currMap).name; // * on the left here turns a pointer into a reference 
+0

使用指針仍然呈現相同的確切問題。這是令人驚訝的,因爲他們應該100%的工作。 **編輯:**我原本只是通過設計獲得副本,因爲我想讓敵人留在原地,但我認爲並通過,如果我沿着空的瓦片隨機遇到敵人,應該沒問題 – Noxilus

+0

不過,通過即使您正在複製,也會引用const引用。您當前正在傳入副本,然後複製副本,然後覆蓋複製的成員。所以當你只需要複製一次時,你就複製了三次佈局數據。 –

+0

謝謝,這將在未來真正幫助我的C++風格。但是,您認爲導致地圖成員獲取空佈局的問題是什麼? – Noxilus

0

我想你也應該在地圖傳遞到您的updateMap功能:

void Character::UpdateMap(Map map){ 
curMap = map;//and all other initiations depending on your object 
sHandler.ClearScreen(); //In a separate class that does work, is just a call to system("cls") 
sHandler.DisplayMap(curMap); //For loop from 0 to (but not including) the size of the layout vector, uses cout to print each row. Works given the correct layout. 

}

+0

UpdateMap只是簡單地將地圖和重新顯示到屏幕上(例如,當一個貼圖從黃金('G')改爲路徑('')時,只要地圖設置正確,使用SetMap, UpdateMap應該沒有任何特殊參數。 – Noxilus