-3

历史:为什么我们可以重载 -> 而不是 . 操作员?两者都是成员访问运算符,具有相同的意义。

我已经阅读了一些参考资料

http://www.stroustrup.com/bs_faq2.html#overload-dot

为什么 operator-> 可以手动重载?

但是我的疑问仍然存在,为什么我们可以重载 .operator 而不是 ->?

是不是因为 -> 运算符隐式获取返回指针的引用,从而在链调用时进行调用

struct X {
    int foo;
};

struct Y {
    X x;
    X* operator->() { return &x; }
};

struct Z {
    Y y;
    Y& operator->() { return y; }
};

Z z;
z->foo = 42;          // Works!  

z->foo = 42; 此调用转换为 ((z.operator()).opeartor()).operator(),因此 foo 的值设置为 42。

问题:-如果我接受这一点,我还有两点,

1) 为什么 .(dot) 运算符不能以这种方式工作?

2) 如果 -> 运算符不返回对 Y 类的引用怎么办?在这种情况下会是编译错误吗?

4

1 回答 1

4

在阅读了以下内容后,我才了解重载 operator-> 的工作原理:

对于内置类型,表达式 E1->E2 完全等同于 (*E1).E2。如果提供了用户定义的 operator->,则在返回的值上再次调用 operator->,递归地,直到到达返回普通指针的 operator->。之后,将内置语义应用于该指针。

要回答你的第二个问题......让我们再看看你的例子:

struct X { int foo; };

struct Y {
    X x;
    X* operator->() { return &x; } // returns pointer 
};

struct Z {
    Y y;
    Y& operator->() { return y; } // returns reference
};

Z z;
z->foo = 42;          // Works!

调用z->评估为z.y。这不是一个指针,因此递归继续:(z.y)->评估为&(z.y.x). 这是一个指针,结果表达式是(&(z.y.x))->

如果您让 Zs 运算符返回一个指针,则递归停止&(z.y)Y没有 afoo并且编译器会抱怨。

于 2015-09-12T12:55:37.760 回答