C++如何在一个类内嵌入另一个类的多个固定键值对对象
问题根因
C++类定义的本质是向编译器描述类型的内存布局、成员构成,类内的成员声明区域只能写声明语句、以及非静态成员的默认初始化表达式,不能写需要运行期执行的操作语句(比如你写的下标赋值、map元素插入逻辑)。这类执行语句必须放在函数体(构造函数、普通成员函数)内才能被执行,这就是你直接在类声明区写赋值不生效、放到成员函数里就能跑的核心原因。
另外你原来的示例代码还有几个语法错误会直接导致编译失败:
unordered_map<std::string, Distance>的键类型是字符串,你用下标[0]传入整数作为键,类型不匹配- C++列表初始化的键值对之间用逗号分隔,不是冒号,你写的
{"chicagoToNewYork": Distance(101.345)}写法不符合语法规范 - Distance类的构造函数如果设为私有,外部无法创建Distance实例存入map,需要把构造函数设为公有。
固定数据的存放原则
这类和Payment类强绑定、永不更改的固定配置数据绝对不要放在main()函数中初始化:
- 会彻底破坏类的封装性,Payment类本身不持有自己运行依赖的固定数据,任何位置创建Payment实例都要手动预先填充距离数据,漏写就会触发运行时错误
- 数据和类逻辑分散,后续修改配置需要跨文件到main中查找,维护成本极高
- 如果项目中多个位置使用Payment类,会出现大量重复的初始化代码。
最合理的方式是把固定数据作为Payment类的成员统一管理。
具体实现方案
根据你的需求(数据永不更改、统一归属到Payment类下),优先选静态常量成员的实现方式,所有Payment实例共享同一份数据,无额外内存开销,也符合数据归属要求。
方案1:C++17及以上版本(最推荐)
用inline static const修饰unordered_map成员,直接在类内完成初始化:
#include <unordered_map> #include <string> class Distance { private: float km; public: // 提供公有构造函数,支持外部创建Distance实例 constexpr Distance(float k) : km(k) {} // 你原本的四舍五入等成员函数 float getKilometers() const { return km; } }; class Payment { private: // 静态常量成员:所有Payment实例共用,只读不可修改,类内直接初始化 inline static const std::unordered_map<std::string, Distance> distancesFromAtoB = { {"chicagoToNewYork", Distance(101.345f)}, {"beijingToShanghai", Distance(1318.0f)} // 后续新增固定距离直接在这个初始化列表里添加即可 }; public: // 成员函数中直接读取使用即可 float queryDistance(const std::string& routeName) const { return distancesFromAtoB.at(routeName).getKilometers(); } };
方案2:C++17之前的老标准适配
老标准不支持类内初始化inline静态成员,需要把静态成员的初始化放到类对应的.cpp实现文件中,避免重复定义:
- 头文件(.h)的Payment类内声明:
class Payment { private: static const std::unordered_map<std::string, Distance> distancesFromAtoB; // 其余成员声明 };
- 实现文件(.cpp)中类外初始化:
const std::unordered_map<std::string, Distance> Payment::distancesFromAtoB = { {"chicagoToNewYork", Distance(101.345f)}, {"beijingToShanghai", Distance(1318.0f)} };
方案3:每个实例独立持有距离表(不推荐)
如果有特殊需求要求每个Payment对象持有独立的距离表副本(固定数据场景下完全没必要,会重复占用内存),可以在Payment的构造函数中完成map的初始化:
class Payment { private: std::unordered_map<std::string, Distance> distancesFromAtoB; public: Payment() { // 构造函数属于函数执行范围,可以写赋值/插入逻辑 distancesFromAtoB["chicagoToNewYork"] = Distance(101.345f); distancesFromAtoB["beijingToShanghai"] = Distance(1318.0f); } };
内容的提问来源于stack exchange,提问作者beginner
相关产品推荐
相关产品推荐

