Answers:
foo->bar
相等的规则(*foo).bar
仅适用于内置运算符。
一元operator *
并不总是具有指针取消引用语义。我可以建立一个库,在其中表示矩阵转置,零个或多个解析器匹配或几乎所有其他内容。
如果重载一元数的任何内容operator *
突然获得了operator ->
您不要求的语义,这可能会使语言更加麻烦。
operator ->
是可单独重载的,因此,如果您想要一个,可以以最小的努力重载一个。
还要注意,这种重载将具有一些非常有趣的属性,例如自动链接operator ->
调用,直到链接中的一个返回原始指针为止。这对于智能指针和其他代理类型非常有用。
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
#include <string>
#include <iostream>
#include <ostream>
struct Foo
{
boost::shared_ptr<std::string> operator -> () const
{
return boost::make_shared<std::string>("trololo");
}
};
int main()
{
Foo foo;
std::cerr << foo->size() << std::endl;
}
->
运算符链,直到它获得指向某事物的原始指针,取消引用和访问它的成员。如果操作符->未链接,则该示例格式不正确,因为shared_ptr不是原始指针。
A->B
最多使用1个附加调用的语法链。C ++->二进制语法的实际作用不是opeartor->
直接调用对象的-而是查看对象的类型A
并检查其原始指针。如果是,则->
对它进行解引用并B
在其上执行,否则它将调用该对象的operator->
,对结果进行解引用(使用本机原始指针或另一个operator->
,然后B
对该结果执行
x->m
应将其解释为(x.operator->())->m
。如果LHS operator->
再次具有适当的过载,则此过程将重复进行,直到只有(*x).m
5.2.5 / 2 的通常效果为止。
“ C ++编程语言”描述了以下事实:这些运算符是不同的,因此它们可以是不同的,但还表示:
如果提供不止这些运营商之一,它可能是明智的,提供等价,只是因为它是明智的,以确保
++x
与x+=1
具有相同的效果x=x+1
进行一个简单的变量x
的一些类如++,+ =,=,和提供了+。
因此,似乎语言设计者提供了单独的重载点,因为您可能希望以不同的方式重载它们,而不是假设您始终希望它们是相同的。
通常,C ++旨在提高灵活性,因此*
和的重载->
是分开的。尽管这样做是非常不寻常的,但是如果您想做的足够糟糕,则可以编写这些重载来完成完全不同的事情(例如,对于在C ++中实现的特定于域的语言可能有意义)。
也就是说,迭代器确实支持这两种用法。在古老的实现中,您可能会找到需要(*iter).whatever
而不是的库iter->whatever
,但是如果是这样,那是实现中的错误,而不是语言的特征。考虑到实现所有标准容器/算法/迭代器所需的工作量,某些早期发行版虽然有些不完整也就不足为奇了,但从未真正打算如此。
(*i).m
有效的迭代器都必须支持i->m
相同的语义。