如何从另一类存储的基类指针vector调用派生类方法?
访问Foo中Bar派生类Log方法的正确实现方案
问题背景
现有类结构如下:
- 基类
Bar包含纯虚Log方法 - 派生类
BarDerived继承Bar并实现Log Foo类持有std::vector<std::unique_ptr<Bar>>类型成员m_BarVec,并提供LogBarVec方法遍历调用Log
原代码片段:
Foo类
class Foo { std::vector<std::unique_ptr<Bar>> m_BarVec; void LogBarVec() const { for(auto& b : m_BarVec) { b->Log(); } } };
Bar基类
class Bar { public: Bar(){}; virtual void Log() const = 0; };
BarDerived派生类
class BarDerived : public Bar { int number = 0; public: BarDerived(float num) : Bar(), number(num){}; void Log() const override { std::cout << "BarDerived number: " << number << std::endl; } };
原main函数
int main() { std::vector<std::unique_ptr<Foo>> foos; for(size_t i = 0; i < foos.size(); i++) { foo->LogBarVec(); } return 0; }
运行时出现错误:"Log is not a member of std::unique_ptr<Bar, std::default_delete<Bar>>",期望输出为:
Foo[0] -> BarDerived number: 4, BarDerived number: 3 Foo[1] -> BarDerived number: 6 etc...
错误原因分析
- 变量未定义:main函数循环中使用了未声明的
foo变量,正确应该是foos[i] - 成员访问权限问题:
Foo::LogBarVec是私有成员,main函数无法调用 - 基类缺少虚析构:
Bar作为多态基类,没有声明虚析构函数,unique_ptr释放对象时会导致未定义行为 - 容器未初始化:
foos是空容器,循环不会执行,也没有填充示例中的Foo和BarDerived实例 - 输出格式不匹配:原
LogBarVec的输出无法达到期望的格式要求
修正后的完整实现
#include <iostream> #include <vector> #include <memory> class Bar { public: Bar() = default; // 添加强制虚析构,避免多态对象释放问题 virtual ~Bar() = default; virtual void Log() const = 0; }; class BarDerived : public Bar { int number = 0; public: BarDerived(float num) : number(static_cast<int>(num)) {}; void Log() const override { std::cout << "BarDerived number: " << number; } }; class Foo { std::vector<std::unique_ptr<Bar>> m_BarVec; public: // 提供添加Bar实例的接口 void AddBar(std::unique_ptr<Bar> bar) { m_BarVec.push_back(std::move(bar)); } // 修改为public成员,外部可调用 void LogBarVec(size_t fooIndex) const { std::cout << "Foo[" << fooIndex << "] -> "; for(size_t i = 0; i < m_BarVec.size(); ++i) { if(i > 0) { std::cout << ", "; } m_BarVec[i]->Log(); } std::cout << std::endl; } }; int main() { std::vector<std::unique_ptr<Foo>> foos; // 初始化Foo[0],添加两个BarDerived实例 auto foo0 = std::make_unique<Foo>(); foo0->AddBar(std::make_unique<BarDerived>(4)); foo0->AddBar(std::make_unique<BarDerived>(3)); foos.push_back(std::move(foo0)); // 初始化Foo[1],添加一个BarDerived实例 auto foo1 = std::make_unique<Foo>(); foo1->AddBar(std::make_unique<BarDerived>(6)); foos.push_back(std::move(foo1)); // 遍历调用LogBarVec,传入索引 for(size_t i = 0; i < foos.size(); ++i) { foos[i]->LogBarVec(i); } return 0; }
关键修正点说明
- 添加虚析构:
Bar类添加virtual ~Bar() = default;,确保多态对象被正确销毁 - 调整访问权限:将
Foo::LogBarVec改为public,同时添加AddBar接口用于填充m_BarVec - 修复变量错误:main循环中使用
foos[i]替代未定义的foo - 初始化容器:填充示例中的
Foo和BarDerived实例,确保循环能执行 - 调整输出格式:修改
LogBarVec,接收Foo的索引参数,输出符合期望的格式,同时处理多个Bar实例的逗号分隔
运行修正后的代码,输出结果与期望一致:
Foo[0] -> BarDerived number: 4, BarDerived number: 3 Foo[1] -> BarDerived number: 6
内容的提问来源于stack exchange,提问作者gerfg grgr
相关产品推荐
相关产品推荐

