类的函数声明后的“默认”是啥意思?

Posted

技术标签:

【中文标题】类的函数声明后的“默认”是啥意思?【英文标题】:What does "default" mean after a class' function declaration?类的函数声明后的“默认”是什么意思? 【发布时间】:2011-09-24 01:47:11 【问题描述】:

我看到default 在类中的函数声明旁边使用。它有什么作用?

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

【问题讨论】:

赋值运算符声明中“=”前面的“&”有什么作用? @dshin 这是ref-qualification of a member function。 【参考方案1】:

这是new C++11 feature。

这意味着你想使用那个函数的编译器生成的版本,所以你不需要指定一个body。

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

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

【讨论】:

= delete 更强:表示禁止使用该函数,但仍参与重载解析。 但是,如果我们想使用编译器生成定义,那么我们是否应该跳过编写该函数而不是“先编写然后将其分配给默认值”? @Mayank Jindal 因为如果我们不提供无参数构造函数,如果我们已经给出了参数化构造函数,编译器会叫。在这种情况下,没有办法跳过默认构造函数的声明。【参考方案2】:

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

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

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

有关详细信息,请参阅标准的第 12.8 节。

【讨论】:

虽然它不仅适用于构造函数和赋值,也适用于operator new/new[]operator delete/delete[]及其重载。【参考方案3】:

它是 C++11 中的新功能,请参阅 here。如果您定义了一个构造函数,但又想为其他构造函数使用默认值,这将非常有用。在 C++11 之前,一旦定义了一个构造函数,就必须定义所有构造函数,即使它们等同于默认值。

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

【讨论】:

关于第二段,你能举个例子吗?【参考方案4】:

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

【讨论】:

【参考方案5】:

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) — 具有相同的声明函数类型(除了可能不同的引用限定符和在 在复制构造函数或复制赋值运算符的情况下,参数类型可能是“引用 non-const T”,其中 T 是成员函数的类的名称),就好像它已被隐式声明一样, 和

(1.3) — 没有默认参数。

2 未定义为已删除的显式默认函数只有在以下情况下才能声明为 constexpr 已被隐式声明为 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

—结束示例]

那么问题当然是可以隐式声明哪些函数以及何时发生,我已经解释过:

What is the <=> ("spaceship", three-way comparison) operator in C++? What are all the member-functions created by compiler for a class? Does that happen all the time? Conditions for automatic generation of default/copy/move ctor and copy/move assignment operator?

【讨论】:

以上是关于类的函数声明后的“默认”是啥意思?的主要内容,如果未能解决你的问题,请参考以下文章

C语言里两个冒号是啥意思?

内部类的公共构造函数是啥意思[重复]

函数的隐式声明是啥意思?

函数声明中单独的星 * 是啥意思? [复制]

声明函数时,“->”在swift中是啥意思?

delphi中函数的声明和调用是啥意思?