20

C++11 增加了告诉编译器创建任何特殊成员函数的默认实现的能力。虽然我可以看到删除函数的价值,但显式默认函数的价值在哪里?只需将其留空,编译器就会这样做。

我能看到的唯一一点是,只有在不存在其他构造函数时才会创建默认构造函数:

class eg {
public:
    eg(int i);
    eg() = default; 
};

但这真的比你现在做的更好吗?

class eg {
public:
    eg(int i);
    eg() {}
};

还是我错过了一个用例?

4

8 回答 8

19

默认构造函数将有一个声明,并且该声明将受制于正常访问规则。例如,您可以保护默认的复制构造函数。如果没有这些新声明,默认生成的成员是公共的。

于 2009-05-05T09:04:01.393 回答
17

Stroustrup 网站上的这些示例可能会帮助您理解这一点:

默认和删除功能——默认控制

“禁止复制”的常用成语现在可以直接表达:

class X {
  // ...

  X& operator=(const X&) = delete;    // Disallow copying
  X(const X&) = delete;
};

相反,我们也可以明确地说我们想要默认的复制行为:

class Y {
  // ...
  Y& operator=(const Y&) = default;   // default copy semantics
  Y(const Y&) = default;

};

明确默认值显然是多余的,但对此效果的评论和(更糟糕的)用户明确定义旨在提供默认行为的复制操作并不少见。让编译器来实现默认行为更简单,更不容易出错,并且通常会导致更好的目标代码。“默认”机制可用于任何具有默认值的函数。“删除”机制可用于任何功能。例如,我们可以像这样消除不需要的转换:

struct Z {
  // ...

  Z(long long);     // can initialize with an long long
  Z(long) = delete; // but not anything less
};
于 2009-05-05T09:34:26.047 回答
12

除了更改生成函数的可访问性(私有/受保护)之外,您还可以将它们设为虚拟。

struct S
{
    virtual ~S();
    virtual S& operator=(const S&);
};

S::~S() = default;
S& S::operator=(const S&) = default;

可以修改默认功能的以下方面:

  • 访问(非公开)
  • 虚拟的
  • 显式(构造函数)
  • 异常规范
  • 参数的常数

但要这样做,必须在类之外定义函数(C++0x Final Committee Draft中的 8.4.2/2 )。

劳伦斯·克劳尔的原始提案的一个版本在这里

感谢Roger Pate的澄清和引用。

于 2009-05-05T10:04:35.057 回答
2

1) 隐式生成的析构函数当前不是虚拟的。所以你需要定义它们以使它们成为虚拟的,在这种情况下它们效率不高。使用 =default,您将同时拥有虚拟和高效作为隐式生成的析构函数。

2) 与隐式生成的相反,它们将具有访问说明符。

3)如果你内联你的默认构造函数,你的类仍然是微不足道的。

这是一篇详细说明此新功能的文章。

于 2009-05-05T10:31:14.757 回答
1

我怀疑能够默认生成复制构造函数实际上很有用。我看不到默认生成默认构造函数的用途,因为正如您所说,您输入的实现会更短。

于 2009-05-05T08:55:36.860 回答
1

请参阅 Scott Meyer 的巨著“ Effective Modern C++ ”中的第 17 条。它描述了生成(或不生成)默认复制构造函数、复制操作和移动操作的许多条件。

换句话说,编译器可能不会“无论如何都做”。但是如果默认的特殊成员函数有意义,用户可以使用“default”关键字明确告诉编译器生成一个默认函数,否则不会生成。

来自第 17 条末尾要记住的事情:

  • 仅为缺少明确声明的移动操作、复制操作或析构函数的类生成移动操作。

  • 复制构造函数只为缺少显式声明的复制构造函数的类生成,如果声明了移动操作,它会被删除。复制赋值运算符仅针对缺少显式声明的复制赋值运算符的类生成,如果声明了移动操作,则将其删除。不推荐在具有显式声明的析构函数的类中生成复制操作。

于 2016-11-03T16:35:12.807 回答
0

如果您有一个具有很多属性的类,则默认值对于复制构造函数更有用。例如,如果你有这个类:

class MyClass {
private:
   int offset;
   std::string name;
   std::vector<Person*> relatives;
   float weight;
   MyClass* spouse;
   Vehicle* car;
   double houseArea;
   Date birth;
   Person* parents[2];

public:
   /* Default constructor will be defined here */
};

而不是以这种方式定义复制构造函数:

MyClass(const MyClass& that) :
   offset(that.offset),
   name(that.name),
   relatives(that.relatives),
   weight(that.weight),
   spouse(that.spouse),
   car(that.car),
   houseArea(that.houseArea),
   birth(that.birth),
   parents(that.parents)
{}

你会这样定义:

MyClass(const MyClass&) = default;
于 2011-09-07T01:46:16.213 回答
0

对我来说,它的禁用功能很有用,对于我目前创建的大多数类,我禁用复制和赋值 - 拥有编译器可以识别的功能会很好,而不是依赖于链接器错误。

于 2009-05-05T09:01:33.413 回答