2017-04-02 48 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