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

如何在容器中保存不同类型的数据成员指针?

关于C++数据成员指针的容器存储与相关问题解答

1. 不同类型数据成员指针的容器存储方案

不同类型的非静态数据成员指针(如int C::*和double C::*)是完全独立的类型,没有直接对应void*的无类型兼容方案——因为数据成员指针的底层实现逻辑和普通指针不同,无法通过无类型指针安全兼容。除了std::any,还有两种更实用的替代方案:

方案一:使用std::variant(类型安全的有限类型集合)

如果数据成员类型是已知的有限几种,std::variant是比std::any更安全的选择,它会在编译期检查类型合法性:

#include <variant>
#include <vector>

class C {
public:
    int i;
    double d;
};

int main() {
    using MemberPtr = std::variant<int C::*, double C::*>;
    std::vector<MemberPtr> v{&C::i, &C::d};
    return 0;
}

方案二:封装为多态类(统一操作接口)

如果需要对成员指针执行统一操作(比如设置值),可以定义带虚函数的基类,为每种成员指针实现派生类,容器存储基类指针:

#include <vector>
#include <memory>

class C {
public:
    int i;
    double d;
};

class MemberAccessor {
public:
    virtual void set(C& obj, int value) = 0;
    virtual ~MemberAccessor() = default;
};

class IntMemberAccessor : public MemberAccessor {
private:
    int C::*ptr;
public:
    IntMemberAccessor(int C::*p) : ptr(p) {}
    void set(C& obj, int value) override {
        obj.*ptr = value;
    }
};

class DoubleMemberAccessor : public MemberAccessor {
private:
    double C::*ptr;
public:
    DoubleMemberAccessor(double C::*p) : ptr(p) {}
    void set(C& obj, int value) override {
        obj.*ptr = static_cast<double>(value);
    }
};

int main() {
    std::vector<std::unique_ptr<MemberAccessor>> v;
    v.emplace_back(std::make_unique<IntMemberAccessor>(&C::i));
    v.emplace_back(std::make_unique<DoubleMemberAccessor>(&C::d));
    
    C c;
    v[0]->set(c, 42); // 设置int成员i为42
    v[1]->set(c, 42); // 设置double成员d为42.0
    return 0;
}

2. 使用std::any时的正确转换方式

std::any存储了类型信息,通过std::any_cast可以安全转换回原数据成员指针类型,转换失败时会抛出std::bad_any_cast异常(或使用指针版本返回nullptr):

#include <any>
#include <vector>

class C {
public:
    int i;
    double d;
};

int main() {
    std::vector<std::any> v{&C::i, &C::d};
    C c;
    
    // 指针版本:转换成功返回非空指针,失败返回nullptr
    if (auto ptr = std::any_cast<int C::*>(&v[0])) {
        c.**ptr = 42;
    }
    
    // 异常版本:转换失败抛出异常
    try {
        c.*std::any_cast<double C::*>(v[1]) = 3.14;
    } catch (const std::bad_any_cast& e) {
        // 处理类型不匹配的情况
    }
    return 0;
}

注意:必须明确指定原成员指针的完整类型(如int C::*),不能用模糊类型进行转换。

3. 数据成员指针的学习资料推荐

  • 《C++ Primer》第19章:详细讲解类成员指针的声明、使用场景以及与普通指针的区别
  • 《Effective C++》条款33:讲解成员指针在继承体系中的陷阱与正确使用方式
  • C++标准文档:[dcl.mptr]章节(成员指针声明)和[expr.unary.op]章节(成员指针的解引用操作)
  • 《C++ Core Guidelines》:关于成员指针使用的风格与安全建议

内容的提问来源于stack exchange,提问作者Nkamil

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 14:03:13