在GoogleTest中结合继承正确使用unique_ptr的方法
问题分析与解决方案
直接代码错误
你的测试代码存在空指针解引用的严重问题:
当执行C myC = C(move(myA));时,myA的所有权被完全转移给myC的pA成员变量,此时myA变成空指针。后续调用myA->getSmtInA()会触发未定义行为,大概率导致程序崩溃。
设计逻辑混淆
代码同时使用了**继承(C is-a A)和组合(C has-a A)**两种关系,这通常是设计意图不清晰导致的。需要先明确需求方向:
- 是让C作为A的子类,重写A的方法并维护自身状态?
- 还是让C作为A的包装类(装饰器模式),内部封装一个A实例并代理其操作?
场景1:C作为A的子类(重写方法)
如果需求是让C继承A的行为并扩展,直接重写A的虚方法即可,无需持有额外的A指针:
修正后的类实现
// 基类A补充成员变量与方法实现 class A { public: A() : smtInA(0) {} virtual ~A() {} virtual void setSmtInA(int setSmt); virtual int getSmtInA(void); private: int smtInA; // 存储数据的成员变量,原代码缺失 }; void A::setSmtInA(int setSmt) { smtInA = setSmt; } int A::getSmtInA(void) { return smtInA; } // 子类C:继承A并重写/扩展方法 class C : public A { public: C() : smtInC(0) {} virtual ~C() {} // 重写A的方法,操作子类自身成员 void setSmtInA(int setSmt) override { smtInC = setSmt; } int getSmtInA(void) override { return smtInC; } // 子类自定义方法 void setSmtInC(int setSmt) { smtInC = setSmt; } int getSmtInC(void) { return smtInC; } private: int smtInC; };
对应的GoogleTest测试代码
TEST(Some_Tests, Test1) { C myC; myC.setSmtInC(15); // 直接调用继承自A的方法,已被C重写 int temp = myC.getSmtInA(); EXPECT_EQ(15, temp); }
场景2:C作为A的包装类(装饰器模式)
如果需求是让C封装一个A实例,通过组合扩展功能,需要调整类接口以正确访问内部A实例:
修正后的类实现
// 基类A补充成员变量与方法实现(同场景1) class A { public: A() : smtInA(0) {} virtual ~A() {} virtual void setSmtInA(int setSmt); virtual int getSmtInA(void); private: int smtInA; }; void A::setSmtInA(int setSmt) { smtInA = setSmt; } int A::getSmtInA(void) { return smtInA; } // 包装类C:继承A并持有A实例(装饰器) class C : public A { public: C(unique_ptr<A> upA) : pA(move(upA)) {} virtual ~C() {} // 子类自定义方法:操作内部封装的A实例 void setSmtInC(int setSmt) { pA->setSmtInA(setSmt); } int getSmtInC(void) { return pA->getSmtInA(); } // 提供访问内部A实例的接口(供测试或外部使用) A& getInnerA() { return *pA; } private: unique_ptr<A> pA; };
对应的GoogleTest测试代码
TEST(Some_Tests, Test1) { unique_ptr<A> myA = make_unique<A>(); C myC = C(move(myA)); myC.setSmtInC(15); // 通过C提供的接口访问内部A实例,避免使用已失效的原指针 int temp = myC.getInnerA().getSmtInA(); EXPECT_EQ(15, temp); }
关键注意点
std::unique_ptr的所有权转移:使用move后,原指针会被置空,绝对不能再访问。- 继承与组合的选择:
is-a关系用继承,has-a关系用组合,避免同时混用导致逻辑混乱。
内容的提问来源于stack exchange,提问作者user10207261
相关产品推荐
相关产品推荐

