C++注解

构造函数相关

问题引出

在使用自己定义的类实现某些操作时,可能会出现这样的报错。

error C2280: attempting to reference a deleted function

表示 被引用的函数已被删除的报错

并且表明该函数为拷贝赋值函数。可你发现,你根本就没有定义这个么函数,引用,和被删除的前提就是它之前存在过?那么我们问题就来了。

拷贝赋值函数:Tile &Tile::operator =(const Tile &)

注: Tile 不是模板。

探讨

我们将问题定位在这个拷贝赋值函数上,探讨关于拷贝复制函数是如何出现的

我们都知道,(假设 自定义的名字为Tile)

C++的构造函数有:

  • 默认构造函数 (无参)
  • 析构函数 (无参)
  • 拷贝构造函数
    • (const Tile &)return Tile&
  • 拷贝赋值函数
    • operator= (const Tile &) return Tile&
    • operator= ( Tile &) return Tile&
  • 移动构造函数

    • ( Tile &&)return Tile&
  • 移动赋值函数

    • operator= ( Tile &) return Tile&&

生成这些特殊成员函数(或不生成)的规则比较复杂,每个特殊成员函数有几种不同的状态,对状态进行判断:

  • 隐式声明还是用户声明
  • 默认提供还是用户提供
  • 正常状态还是删除状态

需要知道的原则:

  • 隐式声明的必然是默认提供的;
  • 默认提供的才可能被删除;
  • 用户提供的也必然是用户声明的。

C++默认构造函数是否提供的情况:

  • 如果自定义了一个任意的构造函数,系统将不在提供默认无参构造

  • 如果自定了一个普通构造函数,系统还会提供一个拷贝构造

  • 如果自定义了一个拷贝构造.系统将不在提供默认拷贝构造
  • 如果自定义一个析构函数,系统将不在提供默认的析构函数
  • 没有初始化的非静态 const 数据成员和引用类型数据成员:导致默认提供的默认构造函数被删除。
  • 非静态的 const 数据成员和引用类型数据成员:导致默认提供的拷贝构造函数、拷贝赋值函数、移动构造函数和移动赋值函数被删除。
  • 用户如果没有自己提供一个拷贝构造函数,编译器会隐式声明一个。
  • 用户如果没有自己提供一个拷贝赋值函数,编译器会隐式声明一个。
  • 用户如果自己声明了一个移动构造函数或移动赋值函数:则默认提供的拷贝构造函数和拷贝赋值函数被删除。
  • 用户如果没有自己声明拷贝构造函数、拷贝赋值函数、移动赋值函数和析构函数:编译器会隐式声明一个移动构造函数。
  • 用户如果没有自己声明拷贝构造函数、拷贝赋值函数、移动构造函数和析构函数:编译器会隐式声明一个移动赋值函数。

参考

参考stack overflow 问答帖子

引用其中的回复

The error clearly mentions Tile &Tile::operator =(const Tile &), so it’s about the assignment operator, not the move-assignment operator. You need to implement it for Tile. You’re also missing Tile‘s copy-constructor.

Quote from here :(这也是从cpprereference中原文)

The implicitly-declared or defaulted copy assignment operator for class T is defined as deleted in any of the following is true:

  • T has a non-static data member that is const
  • T has a non-static data member of a reference type.
  • T has a non-static data member that cannot be copy-assigned (has deleted, inaccessible, or ambiguous copy assignment operator)
  • T has direct or virtual base class that cannot be copy-assigned (has deleted, inaccessible, or ambiguous move assignment operator)
  • T has a user-declared move constructor
  • T has a user-declared move assignment operator