C++ 为什么运营商->;手动过载?

C++ 为什么运营商->;手动过载?,c++,pointers,operator-overloading,smart-pointers,C++,Pointers,Operator Overloading,Smart Pointers,如果p->m只是(*p).m的语法糖,这难道没有意义吗?基本上,我编写的每个操作符->都可以按如下方式实现: Foo::Foo* operator->() { return &**this; } 是否有任何情况下,我希望p->m表示(*p).m)以外的其他含义?您可能需要执行一些其他操作,例如递增变量(访问计数)或甚至进行一些安全检查等。另一方面,我从来不需要重载操作符->…我认为它是用于boost中的共享ptr(例如)。这使得它们看起来像普通指针,尽管它们是特殊指针(引

如果
p->m
只是
(*p).m
的语法糖,这难道没有意义吗?基本上,我编写的每个
操作符->
都可以按如下方式实现:

Foo::Foo* operator->()
{
    return &**this;
}

是否有任何情况下,我希望
p->m
表示
(*p).m
)以外的其他含义?

您可能需要执行一些其他操作,例如递增变量(访问计数)或甚至进行一些安全检查等。另一方面,我从来不需要重载操作符->…

我认为它是用于boost中的共享ptr(例如)。这使得它们看起来像普通指针,尽管它们是特殊指针(引用计数AFIK)。

< P>一个用例可能是在C++内部创建DSL时,(尽管它在库中似乎没有超载<代码> ->代码>),在这里您完全改变了传统C++操作符的含义。这是否是一个好主意当然是有争议的。

操作符->()
有一个奇怪的区别,即隐式地被反复调用,而返回类型允许它。显示这一点的最清晰方式是使用代码:

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!  Calls both!
我记得有一次,为了使一个对象在类似智能指针的上下文中充当另一个对象的代理,这种行为是必要的,尽管我记不起细节。我所记得的是,我只能使用
a->b
语法,通过使用这个奇怪的特例,让行为按照我的意图工作;我找不到一种方法让
(*a).b
类似地工作


不确定这是否回答了你的问题;真的,我是说,“好问题,但比这更奇怪!”

常规指针提供
p->m
(*p).m
,其中
p->m
更为常见。如果只允许重载其中一个,那么它将与默认类型不一致。至于为什么不让编译器重写它,简单的答案是,有时候,你不想让操作符->返回t*,其中操作符*返回t&。允许它们单独重载允许您不一定能想到的组合。但是,仅仅因为我们目前想不出任何理由来改变它,就不允许它是愚蠢的。很像,如果您愿意的话,您可以使用一个int128类和重载运算符+=来表示求幂。

这恐怕不会告诉我任何有趣的事情。为什么
shared\u ptr
需要重载
操作符->()
,而不是简单地重载
操作符*()
,让编译器将
p->m
重写为
(*p).m
?这具有明显的一致性优势——您可以使用任意一种语法并获得相同的结果,这肯定是每个人都期望的。那么为什么不这样做呢?+1本身就是原因,但这对我来说是个糟糕的主意。。。就像编写一个改变世界状态的复制ctor一样糟糕(因为有时编译器可以选择调用它或不调用它)。+1但是,即使
操作符->
硬连接到语言中,语言仍然可以执行这个奇怪的规则,对吗?从技术上讲,它会比语法糖浆略多——可能是语法糖浆?你的意思是,如果语言规范要求编译器将
a->b
重写为
(*a).b
,递归调用
操作符*()
还有意义吗?不,因为有时需要在“到达终点”之前停止(即返回指针/类似指针的对象,例如,这样您可以修改它,而不是返回最终指向的对象)。<代码>运算符>())<递归>怪异是可能的(必要的?),因为它不是真正的“适当”2-ARG操作符——第二个“参数”必须是<代码>结构> <代码>字段名,这是不能在C++类型系统中表达的。P.S:我将称之为语法糖蜜——减慢对爬行的理解:PIt似乎是自然而然地从这样一个事实中产生的:对于存在这种递归的类,
x->y
被解释为
(x.operator->())->y
。也许他们认为允许递归是无害的,因此没有禁止它?至少我在ARM中找不到对此的解释。我同意这样一种观点,即仅仅因为你找不到一个好的理由来允许它就禁止它是不好的,所以+1,但是我认为任何支持
->
重载的论点也会支持
的重载,哪个C++不允许你超载,不一定。请记住,至少有一个操作符必须保持非重载状态,这样人们仍然可以随时访问基类?此外,我不清楚为什么
->
更适合重载。j_random\u hacker:让我们以类x为例,假设它重载了两个且只有两个操作符,
操作符和
->
操作符。
操作符返回类y,
->
操作符返回类z,假设类y重载操作符
->
。如果我们调用
x->member
,那么编译器将其转换为
x.operator->()->member
,但是x重载了操作符
,返回y,那么我们调用的是哪个操作符
->
?正是这种模糊性阻止了我们重载操作符
,类似的模糊性也可以发生在其他操作符上,但是在操作符
上发生的更容易@Joe:是的,我认为问题是
->
都不是真正的“操作符”。所有其他运算符都有1, 2个或3个操作数,它们可以用C++描述,而 ./Cuff>和 -> 两个对象操作数和一个操作数必须是“StultFieldNeX”。至少有一个