构造函数中未调用重写的Setup函数问题咨询
为什么派生类的Setup函数在基类构造时未被调用?
这是C++的虚函数调用规则导致的:当基类构造函数执行时,派生类的成员变量还未完成初始化,此时对象的动态类型仅为基类类型。因此,调用虚函数时只会解析到基类的版本,不会触发派生类的重写函数——这是语言层面的保护机制,防止访问未初始化的派生类成员导致未定义行为。
在你的代码中,创建Derived对象时,执行顺序是:
- 进入
Derived构造函数,首先调用Base的构造函数 Base构造函数内调用Setup(),此时对象的动态类型是Base,因此调用的是Base::Setup(),将val_设为1Base构造完成后,才会执行Derived的构造逻辑(此处为空)- 最终
val_的值是1,所以Print()输出1
解决方案
方案1:使用工厂函数(推荐)
通过静态工厂函数创建对象,确保对象完全构造后再调用初始化函数:
#include <memory> #include <iostream> class Base { public: const int& Value() const {return val_;} void Print() const { std::cout << "My value is " << Value() << std::endl; } // 工厂函数,创建Base对象并完成初始化 static std::unique_ptr<Base> Create() { auto obj = std::make_unique<Base>(); obj->Setup(); return obj; } protected: // 构造函数设为protected,强制通过工厂函数创建 Base() = default; void SetValue(double v) {val_ = v;} virtual void Setup() {SetValue(1.0);} private: int val_; }; class Derived : public Base { public: // 派生类的工厂函数 static std::unique_ptr<Derived> Create() { auto obj = std::make_unique<Derived>(); obj->Setup(); return obj; } protected: Derived() = default; void Setup() override {SetValue(2.0);} }; // 使用示例 int main() { auto a = Derived::Create(); a->Print(); // 输出My value is 2 return 0; }
方案2:传递初始化参数给基类构造
如果Setup仅用于设置初始值,可以直接将初始值作为参数传递给基类构造函数,避免虚函数调用:
#include <iostream> class Base { public: // 显式构造函数,接收初始值 explicit Base(int initial_val = 1) : val_(initial_val) {} const int& Value() const {return val_;} void Print() const { std::cout << "My value is " << Value() << std::endl; } protected: void SetValue(double v) {val_ = v;} // 若无需其他初始化逻辑,可去掉Setup函数 private: int val_; }; class Derived : public Base { public: // 传递初始值2给基类构造 Derived() : Base(2) {} }; // 使用示例 int main() { Derived a; a.Print(); // 输出My value is 2 return 0; }
方案3:两阶段初始化
明确区分对象构造和初始化步骤,构造完成后手动调用初始化函数:
#include <iostream> class Base { public: Base() = default; // 手动调用的初始化函数 void Initialize() { Setup(); } const int& Value() const {return val_;} void Print() const { std::cout << "My value is " << Value() << std::endl; } protected: void SetValue(double v) {val_ = v;} virtual void Setup() {SetValue(1.0);} private: int val_; }; class Derived : public Base { protected: void Setup() override {SetValue(2.0);} }; // 使用示例 int main() { Derived a; a.Initialize(); // 必须手动调用初始化 a.Print(); // 输出My value is 2 return 0; }
内容的提问来源于stack exchange,提问作者kstn
相关产品推荐
相关产品推荐

