请花时间查看下面的代码并回答我的相关问题
class Vector
{
public:
int x, y;
/* Constructor / destructor / Other methods */
Vector operator + (Vector & OtherVector);
Vector & operator += (Vector & OtherVector);
};
Vector Vector::operator + (Vector & OtherVector) // LINE 6
{
Vector TempVector;
TempVector.x = x + OtherVector.x;
TempVector.y = y + OtherVector.y;
return TempVector;
}
Vector & Vector::operator += (Vector & OtherVector)
{
x += OtherVector.x;
y += OtherVector.y;
return * this;
}
Vector VectorOne;
Vector VectorTwo;
Vector VectorThree;
/* Do something with vectors */
VectorOne = VectorTwo + VectorThree;
VectorThree += VectorOne;
这段代码是从一本书中删除的,但在那里没有得到很好的解释。 具体来说,我无法从第6行理解该程序。构造函数和运算符都不会重载。请解释运算符重载和副本构造函数如何在此程序中运行。
编辑:我们为什么要使用引用运算符?
答案 0 :(得分:1)
6: Vector operator + (Vector & OtherVector);
7: Vector & operator += (Vector & OtherVector);
那些声明运算符重载。它们必须表明您确实想要重载运算符。有关以下返回值的更多信息:
10: Vector Vector::operator + (Vector & OtherVector)
11: {
12: Vector TempVector;
13: TempVector.x = x + OtherVector.x;
14: TempVector.y = y + OtherVector.y;
15: return TempVector;
16: }
返回TempVector的副本,该副本添加向量的x和y分量。这允许以下用法(假设已经定义了赋值运算符:
24: Vector VectorOne;
25: Vector VectorTwo;
26: Vector VectorThree;
27: /* Do something with vectors */
28: VectorOne = VectorTwo + VectorThree;
17: Vector & Vector::operator += (Vector & OtherVector)
18: {
19: x += OtherVector.x;
20: y += OtherVector.y;
21: return * this;
22: }
这个与上面的相同,只是我们添加到调用实例而不是临时变量的细微差别。这导致返回*this
。 this
是指向类的当前实例的指针,因此为了获得其值,您需要使用星号解除引用操作符(如果我对运算符的名称错了,请更正我)。
答案 1 :(得分:1)
operator+
正在创建Vector类的新实例,将两个输入的x和y元素的总和放入该新实例中,然后返回新实例。至少IMO(我无法想象很多不同意见)会写得更好:
Vector Vector::operator+(Vector const &otherVector) const {
// ...
}
...将函数本身及其正确的输入限定为const
,因为它不打算修改任何一个。函数的限定基本上是指左操作数,所以这基本上是说当我们做a = b + c;
之类的事情时,b
和c
都不会被修改(即,正好是你通常会期待。这允许(除其他外)将Vector
类型的临时对象用作操作数,并确保不会无意中修改输入。
operator+=
修改其左操作数,因此它只是将另一个向量中的x和y元素添加到自身。然后它返回对作为左操作数提供的操作数的(修改版本)的引用。这允许操作员链接,例如:
Vector a, b, c;
// code to initialize a, b and c here
a += (b += c);
同样,通过引用const来获取输入会受益:
Vector &Vector::operator+=(Vector const &other) {
// ...
}
在这种情况下,我们不能(并且不希望)const
限定函数本身,因为它 修改其左操作数(同样,正是您所期望的:在a += b
中,我们希望a
更改,b
保持不变。
至少如你所示,类定义不包含显式复制构造函数,这意味着如果复制此类的对象,编译器将为您合成复制构造函数。在应该没有问题的情况下 - 该类中的唯一数据是两个整数,对于成员方式的副本(这是编译器将生成的)通常是正常的。显式复制构造函数的最常见原因是一个包含一个或多个指向它所拥有对象的指针的类(在这种情况下,您还希望看到三/五的规则)。
答案 2 :(得分:1)
第6行重载'+'运算符,而第14行重载'+ ='运算符。例如:
Vector v1,v2,v3;
v1 += v2; // Line 14 takes care of this one
v3 = v1 + v2; // Line 6 takes care of this one
这里的最大区别是'+ ='重载修改了调用运算符的实例内的值(上例中的v1),而'+'运算符获取两个实例并生成第三个修改后的值。希望这很清楚。
答案 3 :(得分:1)
此代码不包含复制构造函数,但复制构造函数用于您动态分配类成员的场景,因此一旦实例或对象超出范围,程序不应该崩溃,因为析构函数将解除分配动态分配的内存,如果你已分别包含delete或free for new或malloc。
现在在第6行遇到运算符重载:当你添加像
这样的对象时VectorOne = VectorTwo + VectorThree;
调用第6行函数,它创建临时对象以对VectorTwo和VectorThree的成员进行添加,然后将temperory对象返回到VectorOne,因此VectorOne接收 TempVector 的按位副本。 。请记住,VectorTwo被隐式传递给此函数,因为它位于重载运算符的左侧
当你添加VectorThree += VectorOne;
之类的对象时,调用函数operator + =()并将VectorThree隐式传递给函数,然后函数返回隐式传递给函数的对象的按位副本。关键字 this 指向在这种情况下调用函数VectorThree的对象。然后返回副本再次保存在VectorThree中。
答案 4 :(得分:0)
第6行和第7行是重载运算符的原型。
Vector & operator += (Vector & OtherVector);
返回类型是Vector引用,Argument是向量引用。运算符是+=
运算符。该函数将在以下行中调用:
VectorThree += VectorOne;
定义在第17行。您可以看到它们的行为与典型的成员函数相同(它们具有this
常量,隐式用于定位x和y)。与+ =运算符的典型情况一样,该函数的作用是使参数VectorOne
的内容保持不变,并将VectorThree
的内容设置为其原始值加VectorOne
,并且返回VectorThree
的新值。您可以自己验证整数类型的+ =运算符与以下代码段的工作方式相同:
int a = 1, b = 2, c;
c = (a += b);
cout << "a: " << a << " b: " << b << " c: " << c << endl;
值得注意的是,类的运算符的实现可以遵循他们想要的任何模型。例如,字符串的+ =运算符是就地追加运算符。通常情况下,如果一个类定义一个+运算符和一个+ =运算符,+运算符将采用2个参数,执行一些操作,并返回第三个值,+ =运算符将采用2个参数,执行一些操作,修改其中一个参数,并返回该值。
同样重要的是要注意,由于两个运算符的参数值都没有改变,你可以将它们设为const,如下所示:
Vector operator + (const Vector & OtherVector);
Vector & operator += (const Vector & OtherVector);
这样做的原因是如果你想将一个const变量传递给一个没有声明其参数const的运算符,你就无法做到,即使它没有改变它们。如果没有为+ =的参数指定const,则以下内容是非法的,如果是:= /,则为合法。
Vector value1;
const Vector value2;
value1 += value2;