操作符重载是否没有引用? [英] Could operator overloading have worked without references?

查看:150
本文介绍了操作符重载是否没有引用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

根据Bjarne Stroustrup,引入了C ++以支持运算符重载:


引用主要是为了支持运算符重载。



C通过值传递每个函数参数,并且按值传递对象的效率低或不适当,用户可以传递指针。在使用操作符重载的情况下,此策略不起作用。在这种情况下,符号的便利是必要的,因为如果对象很大,用户不能期望插入操作符的地址。例如:

  a = b  -  c; 

是可接受的(即常规)符号,但

  a =& b  - & c; 

不是。无论如何,& b - & c 已经在C中有意义,我不想改变。




在语言中有指针和引用是C ++新手的一个常见的混乱来源。



无法Bjarne有通过引入一个特殊的语言规则来解决这个问题,如果一个用户定义的操作符函数存在的话,允许对象参数衰减为指针。



声明和使用减法将看起来像:

  Foo operator-(const Foo * x,const Foo * y); 
a = b - c;

这样的解决方案是否曾被提议/考虑?会有什么严重的缺点吗?



是的,我知道,参考提供了其他优势,由于他们的限制,但这不是重点。

$ b $有趣的是,C与类的赋值运算符看起来像是这样工作的:


通过声明一个名为 operator = 的类成员函数来完成对类[...]的对象赋值。例如:

  class x {
public:
int a;
class y * p;
void operator =(class x *);
};



解决方案

看看如何解决问题: operator - 在指针上调用已经有一个意义。



Foo * 参数定义运算符 - ,但已经存在。



然后你需要一些设计的语义,当使用指针显式调用时,指针算术运算符被调用,当使用对象lvalues调用时,它们衰减为指针,然后重载的版本被称为。



然后在运算符 - ,我得到的参数作为指针,然后我最好确保解除引用那些,如果我需要从那里调用另一个(或相同的)运算符。



你建议一个隐式转换,它与你自己完成的转换有不同的语义。也就是:

  Foo foo; 
bar(foo);

执行从 Foo Foo * ,然后调用具有签名 void bar(Foo *)的函数。



但是这段代码会做完全不同的事情:

  Foo foo; 
bar(& foo);

也会转换为 Foo * ,它也会调用签名 void bar(Foo *)的函数,但它可能是强>功能。 (例如,在 operator - 的情况下,一个是用户重载运算符,另一个是标准指针算术运算符。



然后考虑模板代码。一般来说,隐式转换使模板真的很痛苦,因为传入的类型可能不是你想要操作的类型。



当然,还有更多的实际问题:



引用启用指针无法实现的优化(编译器可以假设它们从不



此外,如果没有匹配可以找到操作符 - ,而不是告诉我 ,编译器会隐式地开始做指针算术,而不是一个破解,但我真的更喜欢错误尽可能早。



C ++的目标之一是使其通用:避免有魔法类型或函数。在现实世界的C ++中,运算符只是具有不同语法的函数。使用这个规则,他们也会有不同的语义。 (如果使用函数语法调用操作符?) operator +(a,b)


According to Bjarne Stroustrup, references were introduced into C++ to support operator overloading:

References were introduced primarily to support operator overloading.

C passes every function argument by value, and where passing an object by value would be inefficient or inappropriate the user can pass a pointer. This strategy doesn't work where operator overloading is used. In that case, notational convenience is essential because users cannot be expected to insert address-of operators if the objects are large. For example:

a = b - c;

is acceptable (that is, conventional) notation, but

a = &b - &c;

is not. Anyway, &b - &c already has a meaning in C, and I didn't want to change that.

Having both pointers and references in the language is a constant source of confusion for C++ novices.

Couldn't Bjarne have solved this problem by introducing a special language rule that allowed object arguments to decay into pointers if a user-defined operator function exists that takes such pointers?

The declaration and usage of subtraction would then have looked like:

Foo operator-(const Foo* x, const Foo* y);
a = b - c;

Was such a solution ever proposed/considered? Would there be any serious downsides to it?

Yes I know, references provide other advantages due to their restrictions, but that's not the point.

Interestingly, the assignment operator of C with classes seems to have worked exactly like that:

Changing the meaning of assignment for objects of a class [...] is done by declaring a class member function called operator=. For example:

class x {
public:
    int a;
    class y * p;
    void operator = (class x *);
};

解决方案

I don't see how this solves the problem: operator- called on pointers already has a meaning.

You'd be defining an operator- for Foo* arguments, but that already exists.

Then you'd need some contrived semantics that "when called explicitly with pointers, the pointer arithmetic operator is called. When called with object lvalues, they decay into pointers, and then the overloaded version is called". Which, to be honest, seems far more contrived, and much less intuitive than just adding references.

And then inside the operator-, I get the arguments as pointers, and then I'd better make sure to dereference those if I need to call another (or the same) operator from there. Otherwise I'd accidentally end up performing pointer arithmetics.

You're proposing an implicit conversion which has different semantics than doing the conversion yourself. That is:

Foo foo;
bar(foo); 

performs an implicit conversion from Foo to Foo*, and then a function with the signature void bar(Foo*) is called.

But this code would do something completely different:

Foo foo;
bar(&foo);

that would also convert to a Foo*, and it would also call a function with the signature void bar(Foo*), but it would potentially be a different function. (In the case of operator-, for example, one would be the user-overloaded operator, and the other would be the standard pointer arithmetic one.

And then consider template code. In general, implicit conversions make templates really painful because the type passed in might not be the type you want to operate on.

Of course, there are more practical problems too:

References enable optimizations that aren't possible with pointers. (The compiler can assume they're never null, and it may be better able to do aliasing analysis)

Moreover, code would fail silently if no matching operator- can be found. Instead of telling me that, the compiler would implicitly start doing pointer arithmetics. Not a deal-breaker, but I really really prefer errors to be caught early where possible.

And one of the goals with C++ was to make it generic: to avoid having "magic" types or functions. In real-world C++, operators are very much just functions with a different syntax. With this rule, they would have different semantics as well. (What if the operator is called with function syntax? operator+(a, b)?

这篇关于操作符重载是否没有引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆