你为什么不能重载'。' C ++中的运算符?


78

能够重载。C ++中的操作符并返回对对象的引用。

您可以超载operator->operator*但不能operator.

是否有技术原因?


4
您能否举一个何时覆盖“。”的示例?操作员?
Toon Krijthe

4
通常,用例是“智能引用”。一种代理。
DDAA

2
@Gamecat:通读建议以添加超载operator.和功能operator.*,它有一些示例。
Mankarse

1
.允许使用@ToonKrijthe周围的空格,因此也许有一些聪明却骇人听闻的动态分发技巧,可以将点积表示为matrix1 . matrix2
mwcz 2015年

Answers:


62

请参阅Bjarne Stroustrup的这句话

操作员。(点)原则上可以使用与->相同的技术来重载。但是,这样做可能会引起有关操作是否用于对象重载的问题。或所指的对象。例如:

class Y {
public:
    void f();
    // ...
};

class X {    // assume that you can overload .
    Y* p;
    Y& operator.() { return *p; }
    void f();
    // ...
};

void g(X& x)
{
    x.f();    // X::f or Y::f or error?
}

这个问题可以通过几种方式解决。在标准化时,尚不清楚哪种方法最好。有关更多详细信息,请参见《 C ++的设计和演变》


我的回答中有TDaEoC ++的完整报价。
DDAA

15
我很想将其抄袭/抄袭拒之门外。引用时,请逐字引用,请勿调整。并使用引号格式。
塞巴斯蒂安·马赫

2
该示例只是重载解决方案的歧义,表明需要更仔细的编程(请参阅:stackoverflow.com/questions/13554606/…)这种情况不应作为不重载的原因operator .
slashmais 2013年

@slashmais不。的理由与operator.明显平行operator->。以及如何进行超载分辨率?
curiousguy 2015年

52

Stroustrup说C ++应该是一种可扩展的语言,而不是可变语言。

点(属性访问)运算符被认为与语言的核心过于接近,以至于无法进行重载。

请参阅第242页的C ++的设计和演进,第11.5.2节“智能引用”

当我决定允许运算符重载时->,我自然地考虑了是否.可以同样重载运算符。

当时,我认为以下参数是结论性的:如果obj是类对象,则对该对象的类的obj.m每个成员都有含义m。我们尝试通过重新定义内置操作来使语言不可变(尽管由于=迫切需要和一元规则而违反了该规则&)。

如果我们允许.对某个类进行重载X,则将无法X通过常规方式访问的成员;我们将不得不使用和指针->,但->&可能已被重新定义。我想要一种可扩展的语言,而不是一种可变的语言。

这些论据是有说服力的,但不是结论性的。特别是,1990年,吉姆·阿德考克(Jim Adcock)提议允许操作员. 完全按操作员的方式进行重载->

此引用中的“我”是Bjarne Stroustrup。您不能比这更有权威。

如果您想真正理解C ++(如“为什么这样做”),则应该绝对阅读这本书。


28

Stroustrup 对这个问题有一个答案

操作员。(点)原则上可以使用与->相同的技术来重载。但是,这样做可能会引起有关操作是否用于对象重载的问题。或所指的对象。例如:

class Y {
public:
    void f();
    // ...
};
class X {   // assume that you can overload .
    Y* p;
    Y& operator.() { return *p; }
    void f();
    // ...
};
void g(X& x)
{
    x.f();  // X::f or Y::f or error?
}

这个问题可以通过几种方式解决。在标准化时,尚不清楚哪种方法最好。有关更多详细信息,请参见D&E


1
请参阅我对安东答案的评论
slashmais,

1

这很容易理解,如果您通过运算符调用的内部机制,可以说一个类复合体的实部可以有两个成员r,虚部可以有两个成员。假设Complex C1(10,20),C2(10,2) // //我们假设类中已经有两个参数的构造函数。现在,如果将C1 + C2作为语句编写,则编译器将尝试在复数上查找+运算符的重载版本。现在我们假设我重载+运算符,因此 C1 + C2在内部翻译为c1.operator +(c2) 现在假设您可以重载'。操作员。所以现在考虑以下调用C1.disp() //显示复杂对象的内容现在尝试将其表示为内部表示 C1.operator。(------),完全是一团糟。这就是我们不能超载'。'的原因。算子


1
有人说内部翻译不应调用重载operator.
curiousguy
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.