如何实现派生类构造后自动调用基类sanitycheck且不修改派生类构造?
实现派生类构造后自动调用基类sanitycheck的方案
要让所有继承Base的派生类在构造函数执行完毕后自动调用Base::sanitycheck,且不修改Derived的构造代码,我们可以通过修改基类Base的实现来达成目标,以下是两种可行方案:
方案一:工厂函数(构造后立即调用sanitycheck)
该方案通过给Base添加模板工厂函数,强制用户通过工厂创建派生类对象,在工厂内部完成构造后立即调用sanitycheck,完全匹配期望的输出顺序。
修改后的完整代码:
#include<iostream> std::ostream& o = std::cout; struct Base { void sanitycheck() { o << "base checks\n"; } protected: // 将基类构造函数设为protected,强制用户通过工厂函数创建对象 Base() { o << "make base\n"; } public: // 模板工厂函数,支持所有派生类 template<typename Derived> static Derived create() { Derived d; d.sanitycheck(); return d; } }; // Derived代码完全无需修改 struct Derived : Base { Derived() { o << "make derived\n"; } }; // Dummy类可保留(本方案未使用) struct Dummy { Base& base; Dummy(Base& base) :base(base) {} ~Dummy() { base.sanitycheck(); } }; int main() { // 通过工厂函数创建Derived对象 Derived x = Base::create<Derived>(); /* 输出: make base make derived base checks */ }
方案说明:
- 将
Base的构造函数设为protected,避免用户直接构造Base或直接用Derived x;的方式创建派生类对象,必须通过工厂函数。 - 工厂函数
create构造派生类对象后,立即调用sanitycheck,保证输出顺序完全符合要求。 Derived的代码完全不需要修改,满足题目限制。
方案二:利用RAII成员(对象销毁时调用sanitycheck)
如果允许sanitycheck在对象销毁时执行,可以利用Dummy类作为Base的成员,借助RAII特性,在对象生命周期结束时自动触发检查。
修改后的完整代码:
#include<iostream> std::ostream& o = std::cout; // 先声明Base,避免Dummy编译错误 struct Base; struct Dummy { Base& base; Dummy(Base& base) :base(base) {} ~Dummy() { base.sanitycheck(); } }; struct Base { void sanitycheck() { o << "base checks\n"; } // 添加Dummy成员,构造时绑定当前Base对象 Dummy dummy; Base() : dummy(*this) { o << "make base\n"; } }; // Derived代码完全无需修改 struct Derived : Base { Derived() { o << "make derived\n"; } }; int main() { // 将对象放在局部作用域中,离开作用域时销毁 { Derived x; } /* 输出: make base make derived base checks */ }
方案说明:
- 在
Base中添加Dummy类型的成员变量,构造时传入当前Base对象的引用。 - 当
Derived对象销毁时,会先销毁Base的成员变量dummy,dummy的析构函数自动调用sanitycheck。 - 若直接在main中声明
Derived x;,base checks会在main函数结束时输出;若将对象放在局部作用域中,输出顺序则和期望一致。
内容的提问来源于stack exchange,提问作者user22056011
相关产品推荐
相关产品推荐

