47

我了解正常的运算符重载。编译器可以直接将它们转换为方法调用。我对 -> 运算符不是很清楚。我正在编写我的第一个自定义迭代器,我觉得需要 -> 运算符。我看了一下stl源代码并实现了我自己的:

MyClass* MyClassIterator::operator->() const
{
    //m_iterator is a map<int, MyClass>::iterator in my code.
    return &(m_iterator->second);
}

然后我可以使用 MyClassIterator 的实例,例如:

myClassIterator->APublicMethodInMyClass().

看起来编译器在这里做了两个步骤。1. 调用 ->() 方法获取一个临时的 MyClass* 变量。2. 在临时变量上调用 APublicMethodInMyClass 使用它的 -> 操作符。

我的理解正确吗?

4

2 回答 2

95

Theoperator->在语言中具有特殊的语义,当重载时,它会将自身重新应用于结果。虽然其余运算符仅应用一次,operator->但编译器将根据需要应用多次以获取原始指针并再次访问该指针所引用的内存。

struct A { void foo(); };
struct B { A* operator->(); };
struct C { B operator->(); };
struct D { C operator->(); };
int main() {
   D d;
   d->foo();
}

在前面的示例中,在表达式d->foo()中,编译器将获取对象d并将其应用于operator->它,这会产生一个类型为 的对象C,然后它将重新应用运算符以获取 的实例B,重新应用并获取A*,然后取消引用该对象并获取指向的数据。

d->foo();
// expands to:
// (*d.operator->().operator->().operator->()).foo();
//   D            C            B           A*
于 2012-05-21T02:35:03.443 回答
33
myClassIterator->APublicMethodInMyClass()

只不过是以下内容:

myClassIterator.operator->()->APublicMethodInMyClass()

对重载的第一次调用operator->会为您提供某种类型的指针,该指针具有可访问(来自您的调用站点)的成员函数,称为APublicMethodInMyClass(). resolve 遵循通常的函数查找规则APublicMethodInMyClass(),当然,这取决于它是否是虚拟的。

不一定有临时变量;编译器可能会也可能不会复制&(m_iterator->second). 很可能,这将被优化掉。但是不会创建临时类型的对象MyClass

通常的警告也适用于m_iterator——确保您的调用不会访问无效的迭代器(vector例如,如果您正在使用)。

于 2012-05-20T22:46:40.040 回答