这两天看到《C++ Primer》重载运算符部分,其他的都还简单,就是成员访问运算符稍显复杂,特别是箭头运算符->。
1 | class StrBolbPtr { |
其中->函数的返回语句可以这样理解:对StrBolbPtr类的一个对象调用解引用运算符*,对返回值取地址,得到一个指向该地址的指针。1
2
3
4StrBlob a1 = {"h1", "bye", "now"};
StrBlobPtr p(a1);
cout << p->size() << endl;
cout << (*p).size() << endl;
从这里看不到与声明的对应,就像a+b形式的加运算符,编译器会解释为a.operator+(b);那么a->size()应该解释为a.operator->(size())才对,但声明中并没有参数,而是直接返回一个指针,这是为什么呢?
《C++ Primer》中给出的解释:
对于形如
point->mem的表达式来说,point必须是指向类对象的指针或者是一个重载了operator->的类的对象。
- 如果
point是指针,则应用内置的箭头运算符,表达式等价于(*point).mem。首先解引用该指针,然后从所得的对象中获取指定的成员。- 如果
point是定义了operator->的类的一个对象,则使用point->operator->()的结果来获取mem。其中,如果该结果是一个指针,则执行第一步;如果该结果本身含有重载的operator->(), 则重复第二步。
这样,我们重新对p->size()解释:
- 首先执行上述第二步,调用
p.operator->()返回指向a1的首元素的指针。 - 然后执行第一步,应用
string内置的箭头运算符,取内置类型string的成员函数size()。
这里再给出一个两层箭头运算符的例子,更好的说明第二步1
1 | #include <iostream> |
运行结果为1
2
3
4
5
6
7
8w->a 7
w.operator->() 0x7fff6b46d6a0
w.operator->()->a 7
w2->a 7
&w2.operator->() 0x7fff6b46d690
w2.operator->()->a 7
w2.operator->().operator->() 0x7fff6b46d6a0
w2.operator->().operator->()->a 7
重点是w2->a,它相当于w2.operator->().operator->()->a。具体过程就是:先应用Wrapper2的成员函数operator->() 得到一个Wrapper1类的对象,然后继续应用Wrapper1的成员函数operator->()得到一个指针,最后获取指针指向Origin类的对象的数据成员a。