为什么派生类不使用基类运算符=(赋值运算符)?

Why doesn't a derived class use the base class operator= (assignment operator)?

本文关键字:赋值运算符 运算符 基类 派生 为什么      更新时间:2023-10-16

下面是一个实际问题的简化版本。代码似乎不是调用Base::operator=(int),而是生成一个临时Derived对象并复制该对象。为什么不使用基本赋值运算符,因为函数签名似乎完全匹配?这个简化的示例没有显示任何不良影响,但原始代码在析构函数中有一个副作用,会导致各种破坏。

#include <iostream>
using namespace std;
class Base
{
public:
   Base()
   {
      cout << "Base()n";
   }
   Base(int)
   {
      cout << "Base(int)n";
   }
   ~Base()
   {
      cout << "~Base()n";
   }
   Base& operator=(int)
   {
      cout << "Base::operator=(int)n";
      return *this;
   }
};
class Derived : public Base
{
public:
   Derived()
   {
      cout << "Derived()n";
   }
   explicit Derived(int n) : Base(n)
   {
      cout << "Derived(int)n";
   }
   ~Derived()
   {
      cout << "~Derived()n";
   }
};
class Holder
{
public:
   Holder(int n)
   {
      member = n;
   }
   Derived member;
};
int main(int argc, char* argv[])
{
   cout << "Startn";
   Holder obj(1);
   cout << "Finishn";
   return 0;
}

输出为:

Start
Base()
Derived()
Base(int)
Derived(int)
~Derived()
~Base()
Finish
~Derived()
~Base()

http://ideone.com/TAR2S

这是

编译器生成的operator=方法与成员函数隐藏之间的微妙交互。由于 Derived 类没有声明任何运算符 = 成员,因此编译器隐式生成了一个成员:Derived& operator=(const Derived& source) 。此运算符 = 在基类中隐藏了运算符 =,因此无法使用它。编译器仍然能够通过使用 Derived(int) 构造函数创建一个临时对象并使用隐式生成的赋值运算符复制它来完成赋值。

因为执行隐藏的函数是隐式生成的,而不是源代码的一部分,所以很难发现。

这可以通过在int构造函数上使用 explicit 关键字来发现 - 编译器会发出错误,而不是自动生成临时对象。在原始代码中,隐式转换是一个常用的功能,因此没有使用explicit

解决方案相当简单,Derived 类可以从基类中显式拉入定义:

using Base::operator=;

http://ideone.com/6nWmx