C++可以重载运算符, 其中中括号 "[]", 通常在其它地方用于表示下标的操作符, 重载自然也是用于"获得或者设置某个属性"这么个功能.
最简单的莫过于返回一个地址, 做的操作自然都被看光了.
class Opol { public: Opol() { memset(a,0,10); } int & operator [] (int k) { return a[k]; } private: int a[10]; }
如上的代码返回的是一个地址, 当你对返回的结果进行操作的时候, 对应内存的值被修改, class Opol 中对应的值自然也被随之修改了。
但是这个显然不能满足我们的各种奇葩的要求. 比如我要做一个基于文件的字典, getter 要做的事情是从文件中获得对应的内容, 而 setter 要做的事情是将对应的值写回文件. 而普通的地址引用是无法完成这样的操作的, 我们显然需要一些更有力的操作.
class Opol { public: int get(int k) const { return a.at(k); } void set(int k, int v) { if (a.find(k) == a.end()) { a.insert(std::pair<int, int>(k, v)); } else { a[k] = v; } } private: map<int, int> a; };
最简单的莫过于如上那样写个 set(k, v), get(k) 两个一写, 功能就已经实现了, 但是这个实在是太丑了, 以至于我们几乎都无法再继续写代码了, 我知道, 一定有更好的办法来实现这些的。
目光重新移回重载操作符. 操作符并没有强制要求 "必须返回 xxx 类型". 一个简单的方法是内部构建一个中间 class, 然后再内部实现 set 和 get.
class Opol { private: class Agent { public: Agent(Opol & m_o, int m_k) : o(m_o), k(m_k) {} // The operator int() allows implicit and explicit casting to ints. // This means that when the CB functionality cannot be applied, // it tries if it works for an int (implicit) and you can directly // cast a Agent object to an int value (by using int(x), (int)x, // dynamic_cast<int>(x) or static_cast<int>(x)). // ref: http://www.cplusplus.com/forum/beginner/33566/ operator int() const { printf("get : %d <- %d\n", k, o.get(k)); return o.get(k); } void operator = (int v) { printf("set : %d -> %d\n", k, v); o.set(k, v); } private: Opol &o; int k; }; public: int get(int k) const { return a.at(k); } void set(int k, int v) { if (a.find(k) == a.end()) { a.insert(std::pair<int, int>(k, v)); } else { a[k] = v; } } Agent operator[] (int k) {return Agent(*this, k);} private: map<int, int> a; };
如上, 简单的添加一个 Agent, 然后返回的结果其实是一个 Agent, 而因为"需要"的是一个 int, 然后调用 Agent 的 operator int() 方法实现 "getter" 的功能. 而当它作为左值的时候, 右值会调用 void operator = (int v), 实现 setter 的功能.
这样我们就可以随便使用中括号了.
Opol o; o[1] = 3; printf("o_1 is : %d\n",static_cast<int>(o[1]));
当然, 这个还不全面, 比如我若打算用个 o[1]++ 那就废了. class Agent 中再添加两个 function 即可达成目标.
int operator++() { printf("pre-increment\n"); o.set(k, o.get(k) + 1); return *this; } int operator++(int) { printf("post-increment\n"); int val = o.get(k); o.set(k, val + 1); return val; }
这时候就可以很容易的使用如下语句了
printf("o_1++ is : %d\n",static_cast<int>(o[1]++)); printf("++o_1 is : %d\n",static_cast<int>(++o[1]));
最后输出结果如下:
$ ./a.out set : 1 -> 3 get : 1 <- 3 o_1 is : 3 post-increment o_1++ is : 3 pre-increment get : 1 <- 5 ++o_1 is : 5
最后, 一个小问题: 怎样实现Opol[][] ?
1 Comment
arm · December 17, 2014 at 12:50
很实用的代码