You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从另一类存储的基类指针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...

错误原因分析

  1. 变量未定义:main函数循环中使用了未声明的foo变量,正确应该是foos[i]
  2. 成员访问权限问题:Foo::LogBarVec是私有成员,main函数无法调用
  3. 基类缺少虚析构:Bar作为多态基类,没有声明虚析构函数,unique_ptr释放对象时会导致未定义行为
  4. 容器未初始化:foos是空容器,循环不会执行,也没有填充示例中的Foo和BarDerived实例
  5. 输出格式不匹配:原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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 08:23:39