如何在容器中保存不同类型的数据成员指针?
关于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
相关产品推荐
相关产品推荐

