C++类成员函数返回类对象:读变量正常,赋值变量失效
我编写了如下C++代码,发现调用ParentClass的getSubsidiaryClass()返回的对象调用putLittleDouble()无法修改成员变量,但读取变量正常;而调用返回引用的getSubsidiaryClassReference()和返回指针的getSubsidiaryClassPointer()则可正常修改。已排除访问权限问题,想了解为何第一种方法失效,后两种可行?
#include <iostream> class SubsidiaryClass { private: double little_double; public: double getLittleDouble() {return little_double;} void putLittleDouble(double input) {little_double = input; return;} }; class ParentClass { private: double little_double; SubsidiaryClass subsidiary_class; public: double getLittleDouble() {return little_double;} void putLittleDouble(double input) {little_double = input; return;} SubsidiaryClass getSubsidiaryClass() {return subsidiary_class;} SubsidiaryClass& getSubsidiaryClassReference() {return subsidiary_class;} SubsidiaryClass* getSubsidiaryClassPointer() {return &subsidiary_class;} }; int main() { ParentClass parent_class; parent_class.getSubsidiaryClass().putLittleDouble(1.1); // does not work, no error message std::cout << parent_class.getSubsidiaryClass().getLittleDouble() << std::endl; parent_class.getSubsidiaryClassReference().putLittleDouble(2.2); // works fine std::cout << parent_class.getSubsidiaryClassReference().getLittleDouble() << std::endl; std::cout << parent_class.getSubsidiaryClass().getLittleDouble() << std::endl; parent_class.getSubsidiaryClassPointer() -> putLittleDouble(3.3); // works fine std::cout << parent_class.getSubsidiaryClassPointer() -> getLittleDouble() << std::endl; // works fine std::cout << parent_class.getSubsidiaryClass().getLittleDouble() << std::endl; return 0; }
核心原因:返回值类型决定操作的是原对象还是副本
1. getSubsidiaryClass() 返回值的问题
这个函数的返回类型是SubsidiaryClass(值类型),调用它时会复制一份ParentClass内部的subsidiary_class对象,返回的是这个临时副本。你调用putLittleDouble(1.1)修改的是这个临时副本的成员变量,执行完这行代码后,这个临时副本就会被销毁,ParentClass里的原对象完全没被改动。
而后续读取时,getSubsidiaryClass()又会生成一个新的副本,读取的是新副本的默认值(double类型默认初始化是0),所以看起来好像读取正常但修改无效。
2. getSubsidiaryClassReference() 返回引用的作用
返回类型SubsidiaryClass&是引用类型,引用可以理解为原对象的“别名”,返回的引用直接指向ParentClass内部的subsidiary_class对象。调用putLittleDouble(2.2)时,操作的就是原对象本身,修改自然会生效,后续不管是通过引用还是再次调用值返回的函数(此时新副本会复制原对象的修改后的值),都能读到正确的结果。
3. getSubsidiaryClassPointer() 返回指针的作用
返回类型SubsidiaryClass*是指针,指针存储的是ParentClass内部subsidiary_class对象的内存地址。通过指针->调用函数时,直接访问的是该地址对应的原对象内存,所以修改操作直接作用在原对象上,效果和返回引用一致。
内容的提问来源于stack exchange,提问作者user26521688

