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

C++如何实现获取类内部所有指定类型的子成员对象

实现方案

标准C++没有内置的反射能力来直接遍历类的成员变量,无法原生实现完全通用的GetObjects<T>()接口,但可以通过以下几种工程化方案实现「新增Command子类实例不需要修改打印逻辑」的需求:

方案1:内置容器统一注册(无第三方依赖,兼容性最好,最推荐)

思路是在App类中维护一个Command指针的容器,构造阶段将所有Command子类成员的指针注册到容器中,后续直接遍历容器即可。新增Command成员时仅需补充一行注册代码,无需修改打印逻辑。
注意:你原代码中子类重复定义了Name和Description成员,会隐藏基类的同名成员,导致基类指针访问时拿到空值,以下代码修正了该问题。

#include <vector>
#include <iostream>
#include <string>

class Command {
public:
    std::string Name;
    std::string Description;
    virtual void Compute() = 0;
    virtual ~Command() = default; // 基类添加虚析构避免内存泄漏
};

class StartCommand : public Command {
public:
    StartCommand() {
        Name = "start";
        Description = "Start the process";
    }
    void Compute() override {
        // 启动进程逻辑
    }
};

class StopCommand : public Command {
public:
    StopCommand() {
        Name = "stop";
        Description = "Stop the process";
    }
    void Compute() override {
        // 停止进程逻辑
    }
};

class App {
public:
    StartCommand startCommand;
    StopCommand stopCommand;

    App() {
        // 新增Command成员仅需在此处添加一行注册代码
        m_commands.push_back(&startCommand);
        m_commands.push_back(&stopCommand);
    }

    // 你需要的泛型接口实现
    template<typename T>
    std::vector<T*> GetObjects() {
        std::vector<T*> result;
        for (auto cmd : m_commands) {
            if (auto typedPtr = dynamic_cast<T*>(cmd)) {
                result.push_back(typedPtr);
            }
        }
        return result;
    }

    void PrintAvailableCommands() {
        std::cout << "All available commands are: " << std::endl;
        for (auto cmd : GetObjects<Command>()) {
            std::cout << cmd->Name << ": " << cmd->Description << std::endl;
        }
    }

private:
    std::vector<Command*> m_commands;
};

方案优点:

  • 无任何第三方依赖,所有C++版本均支持
  • 逻辑简单易懂,问题排查成本低
  • 完全满足需求,新增Command仅需补充一行注册代码

方案2:编译期静态反射(无需手动注册)

如果你的项目允许使用C++17及以上版本,可以借助仅头文件的Boost.PFR库实现完全无手动注册的GetObjects<T>()接口,编译期自动遍历App类的所有成员,筛选符合类型的对象。

#include <boost/pfr.hpp>
#include <vector>
#include <iostream>
#include <string>
#include <type_traits>

// Command、StartCommand、StopCommand类定义同方案1

class App {
public:
    StartCommand startCommand;
    StopCommand stopCommand;

    template<typename T>
    std::vector<T*> GetObjects() {
        std::vector<T*> result;
        // 编译期遍历App的所有成员字段
        boost::pfr::for_each_field(*this, [&result](auto& field) {
            // 筛选继承自T的成员
            if constexpr (std::is_base_of_v<T, std::decay_t<decltype(field)>>) {
                result.push_back(&field);
            }
        });
        return result;
    }

    void PrintAvailableCommands() {
        std::cout << "All available commands are: " << std::endl;
        for (auto cmd : GetObjects<Command>()) {
            std::cout << cmd->Name << ": " << cmd->Description << std::endl;
        }
    }
};

方案优点:

  • 完全不需要手动注册,新增Command成员直接定义即可,无需修改其他代码
  • 所有逻辑在编译期完成,无额外运行时开销
    方案限制:
  • 要求C++17及以上版本,且App类必须为聚合类(无自定义构造函数、无私有非静态成员等)
  • 依赖Boost.PFR库,仅头文件集成,无需编译Boost

内容的提问来源于stack exchange,提问作者Maxime Charrière

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 13:06:04