操作员移动装载的工作原理

How operator oveloading works

本文关键字:工作 移动 操作员      更新时间:2023-10-16

我有下面的代码

class rectangle
{
//Some code ...
int operator+ (rectangle r1)
{
return(r1.length + length);//Length is the 1st argument of r1, r2, r3
}
};

主功能

int main()
{
rectangle r1(10,20);
rectangle r2(40,60);
rectangle r3(30,60);
int len = r1 + r3;
}

在这里,如果我们将在operator+()中看到,我们正在执行r1.length + length。编译器是如何知道return语句中的第二个length属于对象r3而不是r1r2的?我想答案可能在main()中,我们已经写了

int len = r1 + r3;

如果是这样的话,为什么我们需要在中写入

operator+ (....) 
{
r1.lenth + lenth; //Why not length + length?
}

为什么不length + length?因为编译器已经从main()知道first length属于objectr1并且2nd属于objectr3

您混淆了变量名和参数名。在运算符重载中,您将参数命名为r1:

int operator+(rectangle r1)
{
return(r1.length+length);
}

这意味着,无论传递给operator +的参数是什么,在操作符的主体内,它都将被命名为r1(无论其原始名称如何)。

r1.length是参数的长度,length是当前对象(即this->length)的长度。

//为什么不是长度+长度?

这只会返回当前对象长度的两倍。

让我们分析一下代码:

rectangle r1(10,20);
rectangle r2(40,60);
rectangle r3(30,60);
int len = r1+r3;

最后一个调用相当于r1.operator+(r3)。在操作符内部,length表示r1.lengthr1.length表示r3.length。实际上,即使是r3.length也不会,因为您传递的是值,并且会创建一个副本。通常的语法是:

int operator+(const rectangle& r1)
{
return(r1.length+length);
}

此外,添加矩形实际上没有意义,至少你是如何定义的。添加两个矩形会返回长度的总和,这并不直观。它至少应该返回一个不同的形状。

int len=r1+r3;

这被解决为

int len = r1.operator+(r3);

因此,该方法是在r1对象上调用的,对operator+中成员的任何引用都将是对r1的成员的引用,r3是该方法的实际参数。

一个对象内的每个变量都不同于另一个对象的变量。只有当你通过参数将对象传递给编译器时,编译器才会知道。它没有其他方法知道这一点。调用函数时,将在堆栈上创建对象的副本。您在参数列表中指定的名称将是编译器将使用的名称,而与您调用函数时使用的名称无关。

int operator+(rectangle r1)
{
return(r1.length+length);
}
r1 + r3; //In main

在本例中,函数调用中对象的名称为r1。你可以给它起任何名字。编译器在main中被调用时不知道它的名称是r3。您将从函数中返回一个整数。最好创建一个临时对象并按值返回。

运算符类似于class rectangle的成员函数,但具有另一种调用格式。

您也可以根据其他用户的建议,将int len = r1.operator+(r3);作为函数进行调用。

因此,当您使用类中的运算符编写操作时,编译器会尝试将调用与某些给定的运算符相匹配;在您的通话中:

int len = r1+r3;

编译器寻找一个operator+,它返回一些可以放入int中的东西,并接收一个作为参数的rectangle,它找到了你的int operator+(rectangle r1)函数;然后用CCD_ 38参数调用该函数并返回CCD_。

int operator+(rectangle r1)函数的参数是r3副本,因此,这就是为什么在r3上操作而不是在r1r2上操作。

这个问题没有提到,但我认为值得一提:

你的operator+似乎不适合操作符通常遵循的模型,如果你要添加一个rectangle,并从操作中获得一个不同于rectangle的对象,它看起来不像操作符;我认为你必须思考你想要得到什么,rectangle的总结是什么。

作为一个二进制运算符,它通常获取并返回相同类型的对象(为了在操作链中使用它),并且必须是常量,因为它不会更改对象本身:

class rectangle
{
// Reference in order to avoid copy and const because we aren't going to modify it.
// Returns a rectangle, so it can be used on operations chain.
rectangle operator+(const rectangle &r) const
{
rectangle Result;
// Do wathever you think that must be the addition of two rectangles and...
return Result;
}
};
int main()
{
rectangle r1(10,20);
rectangle r2(40,60);
rectangle r3 = r1 + r2;
// Operation chain
rectangle r4 = r1 + r2 + r3;
rectangle r5 = r1 + r2 + r3 + r4;
// Is this what you're looking for?
int width = (r1 + r3).width();
int height = (r1 + r3).height();
}

如果是一元运算符,则参数和返回值也必须是相同的类型,但返回值必须是参与操作的对象:

class rectangle
{
// Reference in order to avoid copy and const because we aren't going to modify it.
// Returns a rectangle, so it can be used on operations chain.
rectangle &operator+=(const rectangle &r) const
{
// Do wathever you think that must be the addition of two rectangles and...
return *this;
}
};
int main()
{
rectangle r1(10,20);
rectangle r2(40,60);
rectangle r3 = r1 + r2;
// Weird operation chain, but it's only an example.
rectangle r4 = (r1 += r2) += r3;
rectangle r5 = (r1 += r2) += (r3 += r4);
}

编译器需要区分矩形的长度成员变量this->lengthr1.length。写入length + length意味着局部作用域中的变量this->length将用于加法的两边。

运算符重载的作用不亚于常规函数调用。

a+b想象成a.operator+(b)

除了奇怪的名字之外,该调用与a.add(b)没有什么不同。

如果函数add签名是int A::add(A x)(其中A是一个类),则将b复制到x中,并在内部添加body-x,A的所有成员都可以访问。

但这对运营商来说并没有什么特别之处。它与参数传递(C++默认为"by copy")变量范围和可见性有关。

如果您能够理解这一点,那么运算符重载应该是显而易见的。如果你做不到,回到"函数、成员函数和参数",在这些概念不清楚之前不要离开那里。