C++成员访问/间接运算符等效性

C++ member access/indirection operator equivalence

本文关键字:运算符 成员 访问 C++      更新时间:2023-10-16

我正在查看有关成员引用运算符(一元*取消引用运算符,->成员访问器运算符)的C++标准以及许多其他相关问题:

C++ - (*)之间的区别。 和 ->?

ptr->hello();/* VERSUS */(*ptr).hello();

C++ * 和 -> 之间的指针差异

我看到大多数答案都说p->m是C++标准(5.2.5,第2段)定义的(*p).m的句法糖:

表达式E1->E2将转换为等效形式(*(E1)).E2

许多评论还指出,由于operator*operator->在类中是可重载的,因此应统一重载它们以确保一致的行为。

这些陈述似乎相互矛盾:如果(根据标准)E1->E2转换为等效形式(*(E1)).E2,那么重载operator->的目的是什么(如标准允许的那样)?

更简单地说,标准的这两个部分是冲突的,还是我误解了标准?
E1->E2等效转换为(*(E1)).E2是适用于所有完整类型还是仅适用于内置类型?

E1 -> E2(*(E1)).E2 的转换仅适用于原始指针类型。对于类类型,E1 -> E2的计算结果为 (E1).operator->().E2 ,如果返回的 operator-> 类型本身不是指针类型,则可能会递归扩展更多的operator->副本。您可以通过创建一个支持 operator* 但不支持operator->的类型并尝试在其上使用箭头运算符来查看这一点;你将收到一个错误,指出operator->未定义。

作为后续行动,通常以使->的语义与指针的语义匹配的方式实现operator * operator ->。你经常看到这样的事情:

PointerType ClassType::operator-> () const {
    return &**this;
}

此表达式解释为

&(*(*this)),

意思是"获取此对象(*this),取消引用它(*(*this)),并获取您找到的内容的地址(&(*(*this)).)。现在,如果您使用规则 E1 -> E2 应该等效于 (*(E1)).E2 ,您可以看到您最终会得到等效的东西。