C++如何重载下标运算符以实现多类型键值对存取
实现支持多类型键值对的下标运算符重载
你需要用vector存储键值对(如"Pi = 3.14159"、"UserName = Bob"),值支持string、bool、int、float、double类型,希望通过以下形式操作:
Foo f; f["Pi"].SetFloat(3.14159); // 添加浮点型键值对 float myFloat = f["Pi"].GetFloat(); // 获取浮点型值 Foo f; f["UserName"].SetStr("Bob"); // 添加字符串型键值对 const char * name = f["UserName"].GetStr();// 获取字符串值
现有代码中,你不知道如何重载下标运算符[],当前框架如下:
Foo & operator[]( const char * pszKey ){ // 此处不知如何实现 }
要求该重载支持查找键、添加键值对或返回对应值的功能,需要示例代码理解实现方式。
你的现有部分代码如下:
const char * va( const char * fmt, ... ) { // va = "VarArgs" // 将值格式化为字符串 } void Foo::SetString( const char * Key, const char * ) { // 私有方法 // 将键值对添加至vector } const char * Foo::GetString( const char * key ) { // 私有方法 // 查找键并返回对应值 } // 省略部分代码... const char * Foo::GetStr( const char* Key ) { // 实现细节 } void Foo::SetStr( const char * Key, const int Value ) { SetStr( Key, va("%i", Value )); } float Foo::GetFloat( const char * Key ) { return (float) atof( GetStr( Key )); } void Foo::SetFloat( const char * Key, float Value ) { // 实现细节 } void Foo::SetInt( const char* Key, int Value ); int Foo::GetInt(const char* Key); void Foo::SetBool( const char* Key, bool Value ); bool Foo::GetBool(const char* Key);
实现思路
你需要一个代理类(比如FooProxy),让operator[]返回这个代理对象,而非Foo&。代理对象持有目标Foo实例的引用和键名,这样就能在代理类的SetXxx/GetXxx方法中调用Foo的对应私有方法,完成键值对的操作。
完整示例代码
#include <vector> #include <string> #include <cstdio> #include <cstdlib> #include <cstdarg> // 先声明Foo类,因为代理类需要引用它 class Foo; // 代理类:承接operator[]的返回值,实现链式调用 class FooProxy { private: Foo& m_foo; const char* m_key; public: FooProxy(Foo& foo, const char* key) : m_foo(foo), m_key(key) {} // 各种Set方法,转发给Foo的对应方法 void SetStr(const char* value) { m_foo.SetString(m_key, value); } void SetInt(int value) { m_foo.SetInt(m_key, value); } void SetFloat(float value) { m_foo.SetFloat(m_key, value); } void SetBool(bool value) { m_foo.SetBool(m_key, value); } // 各种Get方法,转发给Foo的对应方法 const char* GetStr() { return m_foo.GetStr(m_key); } int GetInt() { return m_foo.GetInt(m_key); } float GetFloat() { return m_foo.GetFloat(m_key); } bool GetBool() { return m_foo.GetBool(m_key); } }; // 键值对结构体,存储在vector中 struct KeyValuePair { std::string key; std::string value; KeyValuePair(const char* k, const char* v) : key(k), value(v) {} }; class Foo { private: std::vector<KeyValuePair> m_kvPairs; // 私有方法:查找键对应的索引,找不到返回-1 int findKeyIndex(const char* key) const { for (size_t i = 0; i < m_kvPairs.size(); ++i) { if (m_kvPairs[i].key == key) { return static_cast<int>(i); } } return -1; } // 实现私有SetString方法 void SetString(const char* Key, const char* value) { int idx = findKeyIndex(Key); if (idx != -1) { // 键存在,更新值 m_kvPairs[idx].value = value; } else { // 键不存在,添加新键值对 m_kvPairs.emplace_back(Key, value); } } // 实现私有GetString方法 const char* GetString(const char* key) const { int idx = findKeyIndex(key); if (idx != -1) { return m_kvPairs[idx].value.c_str(); } // 找不到返回空字符串(可根据需求修改错误处理逻辑) return ""; } // 实现va函数(示例) static const char* va(const char* fmt, ...) { static char buffer[256]; va_list args; va_start(args, fmt); vsnprintf(buffer, sizeof(buffer), fmt, args); va_end(args); return buffer; } public: // 重载[]运算符,返回代理对象 FooProxy operator[](const char* pszKey) { return FooProxy(*this, pszKey); } // 公开的Get/Set方法,供代理类调用 const char* GetStr(const char* Key) { return GetString(Key); } void SetStr(const char* Key, const char* Value) { SetString(Key, Value); } void SetStr(const char* Key, int Value) { SetString(Key, va("%i", Value)); } float GetFloat(const char* Key) { return static_cast<float>(atof(GetString(Key))); } void SetFloat(const char* Key, float Value) { SetString(Key, va("%.6f", Value)); } int GetInt(const char* Key) { return atoi(GetString(Key)); } void SetInt(const char* Key, int Value) { SetString(Key, va("%i", Value)); } bool GetBool(const char* Key) { const char* val = GetString(Key); return (val[0] == '1' || val[0] == 't' || val[0] == 'T'); } void SetBool(const char* Key, bool Value) { SetString(Key, Value ? "true" : "false"); } }; // 测试代码 int main() { Foo f; f["Pi"].SetFloat(3.14159f); printf("Pi = %.5f\n", f["Pi"].GetFloat()); f["UserName"].SetStr("Bob"); printf("UserName = %s\n", f["UserName"].GetStr()); f["Age"].SetInt(25); printf("Age = %d\n", f["Age"].GetInt()); f["IsActive"].SetBool(true); printf("IsActive = %s\n", f["IsActive"].GetBool() ? "true" : "false"); return 0; }
关键说明
- 代理类
FooProxy:作为operator[]的返回值,持有Foo的引用和键名,把SetXxx/GetXxx的调用转发给Foo的对应方法,完美实现你要的链式调用语法。 operator[]实现:不需要返回Foo&,直接返回一个FooProxy对象,携带当前的键名和Foo实例引用即可。- 键值对存储:用
vector<KeyValuePair>管理,findKeyIndex方法负责查找键的位置,实现更新/添加逻辑。 - 类型转换:所有类型最终都转成字符串存储在vector中,获取时再转成对应类型,和你现有代码的思路保持一致。
内容的提问来源于stack exchange,提问作者Ariana_N
相关产品推荐
相关产品推荐

