在没有引用参数名称的情况下使用 类 重载复制赋值运算符

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;}
};

我想澄清两点。

  1. 这个复制赋值运算符是如何工作的?
  2. 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;