C++多态问题:调用错误对象的成员函数求助
问题根源与解决方案
核心问题:违反单一定义规则(ODR)
你遇到的多态调用异常本质是C++单一定义规则(One Definition Rule)被违反:
- 在
derived_1.cpp和derived_2.cpp中,你分别定义了完全同名的derivedCallBack_t类,且未通过命名空间等方式隔离。 - C++要求同一程序中每个类的定义必须唯一,链接阶段编译器会将这两个同名类视为同一实体,导致它们的虚函数表被错误合并。最终调用
virtualFunction时,实际执行的是链接器优先选取的版本(比如derived_1.cpp中的实现,导致globalFlag被设为1)。
此外,构造函数写法存在冗余,还可能引发潜在的引用生命周期风险:
_base(base_t(*_derivedCallBack))会先创建临时base_t对象,再通过拷贝构造初始化_base。虽然此处*_derivedCallBack是堆对象,引用不会立即悬垂,但这种写法完全没必要,且易引发误解。
修复方案
1. 隔离同名类(解决ODR问题)
给两个cpp文件中的回调类添加独立命名空间,或直接修改类名避免冲突:
方式一:使用命名空间
修改derived_1.cpp:
#include "base.hpp" namespace derived1 { class derivedCallBack_t : public base_t::callBack_t { public: void virtualFunction(void) { globalFlag = 1; } }; } // namespace derived1 class derived_1_t { public: derived_1_t(void); derived1::derivedCallBack_t* _derivedCallBack; base_t _base; }; derived_1_t::derived_1_t(void): _derivedCallBack(new derived1::derivedCallBack_t()), _base(*_derivedCallBack) // 去掉临时对象,直接初始化 {}
修改derived_2.cpp:
#include <iostream> #include "base.hpp" namespace derived2 { class derivedCallBack_t : public base_t::callBack_t { public: void virtualFunction(void) { globalFlag = 2; } }; } // namespace derived2 class derived_2_t { public: derived_2_t(void): _derivedCallBack(new derived2::derivedCallBack_t()), _base(*_derivedCallBack) // 去掉临时对象,直接初始化 {} derived2::derivedCallBack_t* _derivedCallBack; base_t _base; }; int globalFlag = 0; int main() { derived_2_t derived = derived_2_t(); derived._base.run(); std::cout << "globalFlag " << globalFlag; // 此时会输出2 }
方式二:修改类名
直接将derived_1.cpp中的回调类改为derived1CallBack_t,derived_2.cpp中的改为derived2CallBack_t,从根源避免同名冲突。
2. 修复构造函数初始化方式
将_base(base_t(*_derivedCallBack))简化为_base(*_derivedCallBack),直接用堆对象的引用初始化_base,避免不必要的临时对象创建。
验证结果
修复后运行程序,globalFlag会被正确设为2,符合预期。
内容的提问来源于stack exchange,提问作者Hagai
相关产品推荐
相关产品推荐

