【C++基础】第八十一课:[重载运算与类型转换]成员访问运算符

重载成员访问运算符

Posted by x-jeff on August 9, 2023

【C++基础】系列博客为参考《C++ Primer中文版(第5版)》C++11标准)一书,自己所做的读书笔记。
本文为原创文章,未经本人允许,禁止转载。转载请注明出处。

1.成员访问运算符

在迭代器类及智能指针类中常常用到解引用运算符(*)和箭头运算符(->)。我们以如下形式向StrBlobPtr类添加这两种运算符:

1
2
3
4
5
6
7
8
9
10
11
12
class StrBlobPtr {
public:
	std::string& operator*() const 
	{ auto p = check(curr, "dereference past end");
	  return (*p)[curr]; //(*p)是对象所指的vector
	} 
	std::string* operator->() const 
	{ //将实际工作委托给解引用运算符
	  return & this->operator*();
	}
	//其他成员与之前的版本一致
}

箭头运算符不执行任何自己的操作,而是调用解引用运算符并返回解引用结果元素的地址。

箭头运算符必须是类的成员。解引用运算符通常也是类的成员,尽管并非必须如此。

值得注意的是,我们将这两个运算符定义成了const成员,这是因为与递增和递减运算符不一样,获取一个元素并不会改变StrBlobPtr对象的状态。同时,它们的返回值分别是非常量string的引用或指针,因为一个StrBlobPtr只能绑定到非常量的StrBlob对象。

这两个运算符的用法与指针或者vector迭代器的对应操作完全一致:

1
2
3
4
5
StrBlob a1 = {"hi", "bye", "now"};
StrBlobPtr p(a1); //p指向a1中的vector
*p = "okay"; //给a1的首元素赋值
cout << p->size() << endl; //打印4,这是a1首元素的大小
cout << (*p).size() << endl; //等价于p->size()

1.1.对箭头运算符返回值的限定

和大多数其他运算符一样(尽管这么做不太好),我们能令operator*完成任何我们指定的操作。换句话说,我们可以让operator*返回一个固定值42,或者打印对象的内容,或者其他。箭头运算符则不是这样,它永远不能丢掉成员访问这个最基本的含义。当我们重载箭头时,可以改变的是箭头从哪个对象当中获取成员,而箭头获取成员这一事实则永远不变。

对于形如point->mem的表达式来说,point必须是指向类对象的指针或者是一个重载了operator->的类的对象。根据point类型的不同,point->mem分别等价于:

1
2
(*point).mem; //point是一个内置的指针类型
point.operator()->mem; //point是类的一个对象

除此之外,代码都将发生错误。