- m尝试将一个新的Room指针next直接赋值给currentRoom。这会再次产生错误,因为不能将一个指针直接赋值给另一个指针。我们仍然需要获取指针所指向的对象地址:
currentRoom = &*next;
- 编译多文件程序时,其中一个文件必须包含main函数,链接器使用它作为程序的入口点。
g++ -o -std=c++20 main.cpp main.cpp player.cpp room.cpp
- 通过使用this指针,我们可以明确地指定我们要访问的成员变量,(roomNumber和description是Room类里的成员变量)而不是形参。这避免了混淆,确保代码按预期工作。
void Room::init(int roomNumber, string description, map<string, Room*> exits) {
roomNumber = roomNumber;
description = description;
}//这是错误的,会将形参赋给自身
void Room::init(int roomNumber, string description, map<string, Room*> exits) {
this->roomNumber = roomNumber;
this->description = description;
}//这是正确的。
没有命名冲突风险的时候可以忽略,但是我觉得this指针让代码更易读。
- 在最初编写map时,存储的键值均为string,发现无法将direction和Room链接起来,所以将值的类型改为了Room。
- 考虑到动态更新player所在的Room,改用了指针,指针可以改变指向的对象,而且仅储存地址而不是整个对象。
- 想将新定义的map传入到不同Room里,在Room类中使用this指针来访问exits成员变量并将其更新为传入方法的exits映射
void Room::setExits(map<string, Room*> exits) { this->exits = exits; }
- 由于findExits()方法是Room类的一个成员,当调用room->findExits()时,this已经指向要访问的特定Room实例。所以,不需要向该方法传递要访问的Room,它已经通过this隐式传递。
- 循环的时候,getExit()的调用少了一轮,需要在调试后不断修改 。
- 使用构造函数不太清晰,在Room类里没有定义默认构造函数,在player初始化所在房间的时候调用room出现问题。更改后没有使用构造函数,而是使用了普通的成员函数。
- 添加默认构造函数:
class Room { public: // 默认构造函数 Room() {} ... }
- 运行时,第一个房间的出口都打印正常,在输入一个direction后,下一个房间的description可以正常打印,但是该room类的名为exits的map里没有任何direction,也就是下一个房间里有description却没有任何出口了。更正后将map也作为了Room类里初始化房间函数的一个参数。
- 对8再次更正:将 Room 实例作为值插入 exits 映射时, exits 实际上保存的不是 Room 对象本身,而是 Room 对象的副本。所以从 exits 获取该值时,获得的不是原 Room 对象,而是其副本。而无法在副本上调用方法,只能调用原 Room 对象的方法。所以当 map 中的值代表类时,应使用 Room* 指针作为 exits 映射的值,而不是 Room 实例。从 exits 获取值时,获得的是 Room 对象的实际地址(通过原指针),而不是副本。所以可以使用指针调用 Room 对象上的方法。问题解决。举个栗子:
Room room1; map<string, Room> exits; // 使用 Room 实例作为值,这是错误的 exits["north"] = room1; // exits 现在保存 room1 的副本 // 现在无法调用 room1 方法 - exits["north"] 是一个副本 exits["north"].fun(); // 错误,无法调用对象方法
Room room1; map<string, Room*> exits; // 使用 Room* 指针作为值 exits["north"] = &room1; // 存储 room1 的地址 Room* north = exits["north"]; // 获取 room1 的地址 north->fun(); // 可以调用对象方法
- 默认构造函数应该放在类定义内,与其他构造函数一起。例如:
默认构造函数没有参数,并用于在未指定构造函数参数的情况下初始化类。它将类的所有成员变量初始化为默认值。如果类没有定义任何构造函数,编译器会自动生成一个默认构造函数。但是,一旦定义了任何构造函数,编译器就不再生成默认构造函数。所以如果需要一个默认构造函数,必须显式定义它。默认构造函数应放在公共(public)类定义内,与其他构造函数一起。没有特定的顺序规则,可以按任何需要的顺序定义构造函数。class Player { public: Player() {} // 默认构造函数 Player(string name) { ... } // 其他构造函数 // ... };
- 构造函数和成员函数的主要区别是:
构造函数:- 名称与类名相同
- 无返回类型
- 被自动调用以初始化对象
成员函数:- 可以有任意名称
- 有返回类型(可以是void)
- 必须被调用才会执行
// 构造函数
Room(int roomNumber, string description) {
this->roomNumber = roomNumber;
this->description = description;
}
// 成员函数
void init(int roomNumber, string description) {
this->roomNumber = roomNumber;
this->description = description;
}