在没有引用参数名称的情况下使用 类 重载复制赋值运算符
overloading copy assignment operator with classes without a reference parameter name
我想问一个关于 C++ 中运算符重载的问题。
本人初学C++,一直在学习OOP
考虑以下重载复制赋值运算符:
class Base {
private:
int value;
public:
Base () : value {0}
{
cout << "Base No-args constructor" << endl;
}
Base (int x) : value {x} {
cout << "Base (int) overloaded constructor" << endl;
}
Base (const Base &other) : value {other.value} {
cout << "Base copy constructor" << endl;
}
Base & operator = (const Base &rhs) {
cout << "Base operator=" << endl;
if (this == &rhs)
return *this;
value = rhs.value;
return *this;
}
~ Base () {cout << "Base Destructor" << endl;}
};
我想澄清两点。
- 这个复制赋值运算符是如何工作的?
- operator关键字前的引用是否需要参数名?
我想对(1)给出我的解释。
如果我的 main()
中有以下代码:
Base b {100}; // overloaded constructor
Base b1 {b}; // copy constructor
b = b1; // copy assignment
我认为发生的情况是 a1
调用了无参数构造函数,显然是因为没有参数被传递到对象的构造中。
当初始化 a2
时,会生成 a1
的临时副本,然后根据 Base
class 计算运算符,因此 Base
重载副本赋值块是 运行,a1
对象通过 return *this
返回给引用 a2
.
针对第二个问题解释一下我的想法,
我以为在声明函数或方法时所有参数都需要一个名称(当然我可能错了)。
如果我的重载复制赋值块假设写成:
Base &lhs operator = (const Base &rhs)
我说 lhs
指的是 a2
是对的,但是由于隐含的 this
参数,我们没有对 lhs
做任何事情,我们不需要在运算符之前的 & 符号后给出参数名称?
这个复制赋值运算符是如何工作的?
编辑:
Base& operator=(Base const& rhs) {
cout << "Base operator=\n";
value = rhs.value;
return *this;
}
赋值运算符只是一个函数调用。在这种特殊的 class 情况下,编译器将合成一个做正确事情的编译器,但是如果您希望 cout
side-effect 用于教育目的,那么您做对了。
你也可以用方法函数的方式来调用它:
b.operator=(b1);
b = b1;
只是上面的语法糖。
赋值运算符应该 self-assignment 安全。但一般指导是在不明确检查 self-assignment 案例的情况下使其安全,这是“不好的”,因为它针对病态案例进行了优化。
在您的实施中,没有 self-assignment 检查是安全的。
我更喜欢以 Base const&
的顺序而不是 const Base&
的顺序指定限定符,因为一般规则是“限定符总是绑定到它紧邻的东西”,并且例外一般规则是“......除非限定符先出现,在这种情况下,它然后绑定到它直接右边的东西。”当人们掌握了规则的例外而不是一般规则,然后在头脑中解析 Base*const*
时遇到麻烦时,这就成了一个问题。
operator关键字前的引用是否需要参数名?
它的名字是 *this
。是return类型,不是参数,所以没有参数名。
有些人对“为什么 C++ 使用 this
作为指向自身的指针,而不是作为对自身的引用。”感到困惑。
这是C++演进的历史异常。本来有一个this
指针,还没有在语言中加入引用
事后看来,this
应该是一个参考。但是那艘船已经起航了。
在我自己的代码中,为了让它更易读,我会这样做:
auto& self = *this;
self[i] = 5;
...而不是更令人困惑的 (imo)...
(*this)[i] = 5;
我想问一个关于 C++ 中运算符重载的问题。
本人初学C++,一直在学习OOP
考虑以下重载复制赋值运算符:
class Base {
private:
int value;
public:
Base () : value {0}
{
cout << "Base No-args constructor" << endl;
}
Base (int x) : value {x} {
cout << "Base (int) overloaded constructor" << endl;
}
Base (const Base &other) : value {other.value} {
cout << "Base copy constructor" << endl;
}
Base & operator = (const Base &rhs) {
cout << "Base operator=" << endl;
if (this == &rhs)
return *this;
value = rhs.value;
return *this;
}
~ Base () {cout << "Base Destructor" << endl;}
};
我想澄清两点。
- 这个复制赋值运算符是如何工作的?
- operator关键字前的引用是否需要参数名?
我想对(1)给出我的解释。
如果我的 main()
中有以下代码:
Base b {100}; // overloaded constructor
Base b1 {b}; // copy constructor
b = b1; // copy assignment
我认为发生的情况是 a1
调用了无参数构造函数,显然是因为没有参数被传递到对象的构造中。
当初始化 a2
时,会生成 a1
的临时副本,然后根据 Base
class 计算运算符,因此 Base
重载副本赋值块是 运行,a1
对象通过 return *this
返回给引用 a2
.
针对第二个问题解释一下我的想法,
我以为在声明函数或方法时所有参数都需要一个名称(当然我可能错了)。
如果我的重载复制赋值块假设写成:
Base &lhs operator = (const Base &rhs)
我说 lhs
指的是 a2
是对的,但是由于隐含的 this
参数,我们没有对 lhs
做任何事情,我们不需要在运算符之前的 & 符号后给出参数名称?
这个复制赋值运算符是如何工作的?
编辑:
Base& operator=(Base const& rhs) {
cout << "Base operator=\n";
value = rhs.value;
return *this;
}
赋值运算符只是一个函数调用。在这种特殊的 class 情况下,编译器将合成一个做正确事情的编译器,但是如果您希望 cout
side-effect 用于教育目的,那么您做对了。
你也可以用方法函数的方式来调用它:
b.operator=(b1);
b = b1;
只是上面的语法糖。
赋值运算符应该 self-assignment 安全。但一般指导是在不明确检查 self-assignment 案例的情况下使其安全,这是“不好的”,因为它针对病态案例进行了优化。
在您的实施中,没有 self-assignment 检查是安全的。
我更喜欢以 Base const&
的顺序而不是 const Base&
的顺序指定限定符,因为一般规则是“限定符总是绑定到它紧邻的东西”,并且例外一般规则是“......除非限定符先出现,在这种情况下,它然后绑定到它直接右边的东西。”当人们掌握了规则的例外而不是一般规则,然后在头脑中解析 Base*const*
时遇到麻烦时,这就成了一个问题。
operator关键字前的引用是否需要参数名?
它的名字是 *this
。是return类型,不是参数,所以没有参数名。
有些人对“为什么 C++ 使用 this
作为指向自身的指针,而不是作为对自身的引用。”感到困惑。
这是C++演进的历史异常。本来有一个this
指针,还没有在语言中加入引用
事后看来,this
应该是一个参考。但是那艘船已经起航了。
在我自己的代码中,为了让它更易读,我会这样做:
auto& self = *this;
self[i] = 5;
...而不是更令人困惑的 (imo)...
(*this)[i] = 5;