类中的变量保存了错误的值

Variable in class holds wrong value

本文关键字:错误 变量 保存      更新时间:2023-10-16

我刚开始学习 c++,并且有一些早期的 java 和 c 经验。我决定对课程进行一些实验,以便更多地了解它们。

目前我有2个班级,书和书架。书架由一本书、一个字符串和一个整数组成。Book 由一个字符串和一个称为page的 int 组成。

所有变量都包含预期值,除了我在Book中的 int 页面。它包含一些似乎与任何东西都没有相关性的任意值。我的猜测是,这与我的代码以某种方式弄乱了指向页面的一些重要指针有关。

我尝试将页面更改为 *int 而不是 int,希望我能持有指向值的指针,而不是值本身。但是输出仍然是"错误的",因为取消引用的指针仍然包含错误的值。

我的主要.cpp:

int main(int argc, char** argv) {
Book harrypotter("Harry Potter and the Chamber of Secrets");
Shelf fantasy(harrypotter, "fantasy", 1);
fantasy.getBOOK().setPAGE(15);
std::cout << fantasy.getSUBJECT() << std::endl;
std::cout << fantasy.getSHELFNUMBER() << std::endl;
std::cout << fantasy.getBOOK().getNAME() << std::endl;
std::cout << fantasy.getBOOK().getPAGE(); //this line failes
return 0;
}

货架.hpp

class Shelf {
public:
Shelf();
Shelf(Book book, std::string subject, int shelfnr);
std::string getSUBJECT(){return this->subject;}
Book getBOOK(){return this->book;} //container with the faulty int
int getSHELFNUMBER(){return this->shelfnr;}
private:
Book book;
std::string subject;
int shelfnr;
};

书.hpp

class Book {
public:
Book();
Book(std::string name);
std::string getNAME(){return this->name;}
void setPAGE(int page){this->page = page;}
int getPAGE(){return this->page;} //this returns wrong value!
private:
std::string name;
int page;//this contains wrong value!
};

电流输出:

fantasy
1
Harry Potter and the Chamber of Secrets
-2145318336 (or some other arbitrary number)

我期望的输出:

fantasy
1
Harry Potter and the Chamber of Secrets
15

成员函数Shelf::getBOOK()按值返回数据成员。这意味着将创建副本并将其作为临时对象返回。此行

fantasy.getBOOK().setPAGE(15);

改变临时副本,而不是Shelf实例拥有的对象。因此,您稍后访问的page变量是未初始化的,从中读取是未定义的行为。这就是为什么设置一个有意义的默认值是有利的,例如

class Book {
// ...
int page = 0;
};

修复原始问题可以通过以下方式实现

Book harrypotter("Harry Potter and the Chamber of Secrets");
harrypotter.setPage(15);
// Now, the above book has the desired state, so pass it the Shelf instance:
Shelf fantasy(harrypotter, "fantasy", 1);

或者按照@PaulMcKenzie回答中的建议更改Shelf::getBOOK()签名。

您看不到更改的一个原因是:

Book getBOOK(){return this->book;}

这将返回Book对象的副本。 因此,您正在更改副本,而不是原始Book

如果要更改在Shelf中声明的实际Book对象,则返回一个引用:

Book& getBOOK(){return this->book;}

Book getBOOK(){return this->book;}

您返回book的副本,并对该副本调用setPAGE。原始book永远不会改变。

如果shelf中应该只有一个book(这很奇怪),您可以从shelf本身公开setPAGE(),这将调用book.setPAGE()

如果你打算在shelf上有很多bookgetBOOK()没有任何意义。