C++多继承中Setter修改成员变量时默认构造函数重复执行问题咨询
嘿,我能get到你遇到的困惑!咱们一步步拆解问题,先从你可能踩的坑说起,再给你解决办法。
首先纠正一个关键误解:C++里派生类并不会“继承”基类的构造函数(C++11之后可以用using Base::Base;语法继承,但默认情况下不会)。不过你这里的场景没问题——当你没给派生类写任何构造函数时,编译器会自动帮你生成一个默认构造函数,这个生成的构造函数会自动调用所有基类的默认构造函数,来初始化基类部分的成员,所以派生类对象创建时基类构造执行是正常的。
那你说的“调用Setter时默认构造又被执行,没法修改变量”,大概率是下面两种情况之一:
情况1:你不小心创建了临时对象调用Setter
比如你可能写了这样的代码:
int main() { Derived d; // 这里创建了对象d,基类默认构造执行 Derived().setNum1(10); // 注意!这里是创建了一个临时的Derived对象 cout << d.getNum1() << endl; // 输出0,因为临时对象修改完就销毁了,d根本没被改 return 0; }
这种情况下,Derived()会生成一个临时对象,调用它的Setter后这个对象立刻消失,你原来的d对象完全没被修改,同时临时对象创建时又会执行一遍基类的默认构造,所以你会误以为是Setter触发了构造函数。
解决办法:直接用你已经声明好的派生类对象调用Setter:
int main() { Derived d; d.setNum1(10); // 用已存在的对象d调用Setter d.setNum2(20); // 现在输出就是修改后的值了 cout << "num1: " << d.getNum1() << ", num2: " << d.getNum2() << endl; return 0; }
情况2:基类的Setter函数返回值类型不对
如果你的基类Setter是这样写的:
// 错误示例:返回值是值类型,不是引用 Base1 setNum1(int n) { num1 = n; return *this; }
这时候当你调用d.setNum1(10),函数会返回一个Base1的临时对象,你修改的其实是这个临时对象,原对象d的成员变量根本没变化。
解决办法:让Setter返回引用或者void:
// 正确写法1:返回引用 Base1& setNum1(int n) { num1 = n; return *this; } // 正确写法2:返回void void setNum1(int n) { num1 = n; }
完整的可运行示例代码
#include <iostream> using namespace std; class Base1 { private: int num1; public: Base1() : num1(0) { cout << "Base1默认构造执行" << endl; } // 正确的Setter:返回void void setNum1(int n) { num1 = n; } int getNum1() const { return num1; } }; class Base2 { private: int num2; public: Base2() : num2(0) { cout << "Base2默认构造执行" << endl; } void setNum2(int n) { num2 = n; } int getNum2() const { return num2; } }; // 派生类无需显式写构造函数,编译器会生成默认构造 class Derived : public Base1, public Base2 {}; int main() { Derived d; // 用已创建的对象调用Setter d.setNum1(10); d.setNum2(20); cout << "修改后的值:num1=" << d.getNum1() << ", num2=" << d.getNum2() << endl; return 0; }
运行这个代码,你会看到基类构造只执行一次,并且成员变量被成功修改。
额外提醒
如果之后你需要给派生类添加带参数的构造函数,记得要显式调用基类的构造函数(比如Derived(int a, int b) : Base1(a), Base2(b) {}),不然编译器会尝试调用基类的默认构造,如果基类没有默认构造就会报错。
内容的提问来源于stack exchange,提问作者moayad karimeh

