rhs 是如何工作的?
How does rhs work?
在这里我理解 rhs 表示右手边,但我不明白编译器如何理解 "rhs" 指的是右手边。有人可以解释在什么情况下需要这种重载吗?
MyArray<T>& operator=(const MyArray<T>& rhs);
rhs
只是人们通常对该运算符使用的名称,它没有特殊含义。运算符的定义方式始终使参数成为右侧元素。
编译器不知道 rhs
代表 "right hand side",实际上该变量的名称可以是您喜欢的任何名称。
编译器 "knows" 如何格式化它,因为 operator=
的语法要求它是这样的。
class A
{
public:
A& operator=(const A& other);
};
该语言定义了该运算符的用法,采用以下形式:
A a, b;
a = b;
上面的代码针对名为 a
的 A
实例调用 A::operator=(const &other)
,并将名为 b
的 A
实例用作 [=19] =].
如果你这样做:
int a = 5;
int b = 3;
a = b;
赋值部分实际上只是一个函数调用:
a.operator=(b);
没什么特别的。参数名称无关紧要,只是由 return 类型和参数类型组成的签名,而不是名称。
与任何函数一样,您可以随意调用参数。
将你的例子与赋值运算符一起使用,如果你有类似
MyArray<int> arr1, arr2;
arr1 = arr2;
相当于
MyArray<int> arr1, arr2;
arr1.operator=(arr2);
"right hand side" 只是作为参数传递给普通成员函数。
相同类型实例的标准赋值运算符具有原型
MyArray<T>& operator=(const MyArray<T>&);
通常将名称 rhs
赋予函数参数,因为它在调用运算符时出现在赋值的右侧。它提高了源代码的易读性,仅此而已。
我假设 MyArray 将具有这样的结构。
class MyArray{
public:
int* arr;
int len;
MyArray( int l ){
arr = new int[l];
len = l;
}
~MyArray(){
delete [] arr;
}
};
现在考虑一个场景,其中有 2 个 MyArray 对象
MyArray ob1(3);
for( int i=0; i<3; i++ )
ob1[i]=i*i; // ob1 = {0, 1, 4}
MyArray ob2(3);
for( int i=0; i<3; i++ )
ob2[i]=i+1; // ob2 = {1, 2, 3}
现在如果我们这样做 ob1 = ob2
;编译器会做什么它会使 arr1 指向 arr2,所以如果 Ob2 更改为 {4,5,6} Ob1 也将更改为 {4,5,6},这称为 shallow copy.To 避免场景我们添加这个
MyArray& operator=(const MyArray& rhs){
for( int i=0; i<rhs.len; i++ ) this.arr[i] = rhs[i];
}
现在,如果更改 ob2,ob1 将不会受到影响,因为我们是自己复制数组而不是指针 copy.So,这称为深复制。这是 = 超载的主要场景之一。
在这里我理解 rhs 表示右手边,但我不明白编译器如何理解 "rhs" 指的是右手边。有人可以解释在什么情况下需要这种重载吗?
MyArray<T>& operator=(const MyArray<T>& rhs);
rhs
只是人们通常对该运算符使用的名称,它没有特殊含义。运算符的定义方式始终使参数成为右侧元素。
编译器不知道 rhs
代表 "right hand side",实际上该变量的名称可以是您喜欢的任何名称。
编译器 "knows" 如何格式化它,因为 operator=
的语法要求它是这样的。
class A
{
public:
A& operator=(const A& other);
};
该语言定义了该运算符的用法,采用以下形式:
A a, b;
a = b;
上面的代码针对名为 a
的 A
实例调用 A::operator=(const &other)
,并将名为 b
的 A
实例用作 [=19] =].
如果你这样做:
int a = 5;
int b = 3;
a = b;
赋值部分实际上只是一个函数调用:
a.operator=(b);
没什么特别的。参数名称无关紧要,只是由 return 类型和参数类型组成的签名,而不是名称。
与任何函数一样,您可以随意调用参数。
将你的例子与赋值运算符一起使用,如果你有类似
MyArray<int> arr1, arr2;
arr1 = arr2;
相当于
MyArray<int> arr1, arr2;
arr1.operator=(arr2);
"right hand side" 只是作为参数传递给普通成员函数。
相同类型实例的标准赋值运算符具有原型
MyArray<T>& operator=(const MyArray<T>&);
通常将名称 rhs
赋予函数参数,因为它在调用运算符时出现在赋值的右侧。它提高了源代码的易读性,仅此而已。
我假设 MyArray 将具有这样的结构。
class MyArray{
public:
int* arr;
int len;
MyArray( int l ){
arr = new int[l];
len = l;
}
~MyArray(){
delete [] arr;
}
};
现在考虑一个场景,其中有 2 个 MyArray 对象
MyArray ob1(3);
for( int i=0; i<3; i++ )
ob1[i]=i*i; // ob1 = {0, 1, 4}
MyArray ob2(3);
for( int i=0; i<3; i++ )
ob2[i]=i+1; // ob2 = {1, 2, 3}
现在如果我们这样做 ob1 = ob2
;编译器会做什么它会使 arr1 指向 arr2,所以如果 Ob2 更改为 {4,5,6} Ob1 也将更改为 {4,5,6},这称为 shallow copy.To 避免场景我们添加这个
MyArray& operator=(const MyArray& rhs){
for( int i=0; i<rhs.len; i++ ) this.arr[i] = rhs[i];
}
现在,如果更改 ob2,ob1 将不会受到影响,因为我们是自己复制数组而不是指针 copy.So,这称为深复制。这是 = 超载的主要场景之一。