类的函数声明之后"default"是什么意思?

What does "default" mean after a class' function declaration?

本文关键字:default 是什么 意思 之后 函数 声明      更新时间:2023-10-16

我见过default在类中的函数声明旁边使用。它做什么?

class C {
  C(const C&) = default;
  C(C&&) = default;
  C& operator=(const C&) & = default;
  C& operator=(C&&) & = default;
  virtual ~C() { }
};

这是C++11的一个新特性。

这意味着您希望使用该函数的编译器生成版本,因此不需要指定正文。

您也可以使用= delete来指定您不希望编译器自动生成该函数。

随着移动构造函数和移动赋值运算符的引入,何时生成构造函数、析构函数和赋值运算符的自动版本的规则变得相当复杂。使用= default= delete可以让事情变得更容易,因为你不需要记住规则:你只需要说出你想发生的事情。

这是一个新的C++0x功能,它告诉编译器创建相应构造函数或赋值运算符的默认版本,即只为每个成员执行复制或移动操作的版本。这很有用,因为移动构造函数并不总是默认生成的(例如,如果你有一个自定义的析构函数),不像复制构造函数(对于赋值也是如此),但如果没有什么不重要的东西要写,最好让编译器处理它,而不是每次自己拼写出来。

还要注意,如果您提供任何其他非默认构造函数,则不会生成默认构造函数。如果你仍然想要默认的构造函数,你可以使用这个语法让编译器生成一个。

作为另一个用例,有几种情况下复制构造函数不会隐式生成(例如,如果您提供自定义的移动构造函数)。如果您仍然想要默认版本,可以使用此语法进行请求。

详见本标准第12.8节。

它在C++11中是新的,请参阅此处。如果您定义了一个构造函数,但希望对其他构造函数使用默认值,那么它可能非常有用。在C++11之前,一旦定义了一个构造函数,就必须定义所有的构造函数,即使它们与默认值相等。

还要注意,在某些情况下,不可能提供一个用户定义的默认构造函数,该构造函数的行为与默认初始化下编译器合成的构造函数相同。default允许您恢复这种行为。

我在这些答案中没有提到的另一个用例是,它可以轻松地更改构造函数的可见性。例如,您可能希望friend类能够访问复制构造函数,但不希望它公开可用。

C++17 N4659标准草案

https://github.com/cplusplus/draft/blob/master/papers/n4659.pdf11.4.2";显式默认函数":

1表单的函数定义:

attribute-specifier-seq opt decl-specifier-seq opt declarator virt-specifier-seq opt = default ;

称为显式默认定义。明确默认的功能应为

  • (1.1)--是一个特殊的成员函数,

  • (1.2)-具有相同的声明函数类型(除了可能不同的ref限定符和在复制构造函数或复制赋值运算符的情况下,参数类型可以是"引用非常数T",其中T是成员函数类的名称),就好像它是隐式声明的一样,和

  • (1.3)--没有默认参数。

2未定义为已删除的显式默认函数只能在已隐式声明为constexpr。如果函数在其第一个声明中被显式默认,则为如果隐式声明为.,则隐式地认为是constexpr

3如果显式默认的函数是用noexcept说明符声明的,该说明符不会产生相同的结果异常规范作为隐式声明(18.4),然后

  • (3.1)——如果函数在其第一个声明中被明确默认,则将其定义为已删除;

  • (3.2)--否则,程序不正确。

4[示例:

struct S {
  constexpr S() = default;            // ill-formed: implicit S() is not constexpr
  S(int a = 0) = default;             // ill-formed: default argument
  void operator=(const S&) = default; // ill-formed: non-matching return type
  ~ S() noexcept(false) = default;    // deleted: exception specification does not match
private:
  int i;                              // OK: private copy constructor
  S(S&);
};
S::S(S&) = default;                   // OK: defines copy constructor

--结束示例]

5显式默认函数和隐式声明函数统称为默认函数实施应为它们提供隐含的定义(15.1 15.4,15.8),这可能意味着定义它们被删除。如果函数是用户声明的,并且没有显式默认或删除,则它是用户提供的在其第一次声明中。用户提供的显式默认函数(即,在第一个函数之后显式默认声明)是在它被明确默认的点上定义的;如果这样的函数隐式定义为已删除,程序格式不正确。[注意:在函数的第一次声明后将其声明为默认值可以提供高效的执行和简洁的定义,同时为不断发展的代码提供稳定的二进制接口基本。--尾注]

6[示例:

struct trivial {
  trivial() = default;
  trivial(const trivial&) = default;
  trivial(trivial&&) = default;
  trivial& operator=(const trivial&) = default;
  trivial& operator=(trivial&&) = default;
  ~ trivial() = default;
};
struct nontrivial1 {
  nontrivial1();
};
nontrivial1::nontrivial1() = default;       // not first declaration

--结束示例]

当然,问题是哪些函数可以隐式声明,什么时候会发生,我已经在上解释过了

  • 什么是<>("宇宙飞船",三元比较)运算符在C++中
  • 编译器为类创建的所有成员函数是什么?这种情况经常发生吗
  • 自动生成默认/复制/移动运算符和复制/移动分配运算符的条件