[TOC]

概述

首先,什么是默认功能呢(Defaulted Function)

明确默认的函数声明式一种新的函数声明方式,在C++11发布时做出了更新。C++11允许添加“=default”说明符到函数声明的末尾,以将该函数声明为显示默认构造函数。这就使得编译器为显示默认函数生成了默认实现,它比手动编程函数更加有效。

例如,每当我们声明一个有参构造函数时,编译器就不会创建默认构造函数。在这种情况下,我们可以使用default说明符来创建默认说明符。以下代码演示了如何创建:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// use of defaulted functions
#include <iostream>
using namespace std;

class A {
public:
// A user-defined
A(int x){
cout << "This is a parameterized constructor";
}

// Using the default specifier to instruct
// the compiler to create the default implementation of the constructor.
A() = default;
};

int main(){
A a; //call A()
A x(1); //call A(int x)
cout<<endl;
return 0;
}

在上面的例子中,我们不必指定构造函数A()的主体,因为通过附加说明符’= default’,编译器将创建此函数的默认实现。

那么使用此“=default”符号有什么限制?

  • 默认函数需要用于特殊的成员函数(默认构造函数,复制构造函数,析构函数等),或者没有默认参数。例如,以下代码解释了非特殊成员函数不能默认:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// non-special member functions can't be defaulted(非特殊成员函数不能使用default) 
class B {
public:
// Error, func is not a special member function.
int func() = default;

// Error, constructor B(int, int) is not a special member function.
B(int, int) = default;

// Error, constructor B(int=0) has a default argument.
B(int = 0) = default;
};
int main() {
return 0;
}

运行结果:

当我们可以使用“{}”简单的空的实体时,使用’= default’有什么优点?

尽管两者可能表现相同,但使用default而不是使用{}仍然有一定的好处。以下几点做了一定的解释:

给用户定义的构造函数,即使它什么也不做,使得类型不是聚合,也不是微不足道的。如果您希望您的类是聚合类型或普通类型(或通过传递性,POD类型),那么需要使用’= default’。
使用’= default’也可以与复制构造函数和析构函数一起使用。例如,空拷贝构造函数与默认拷贝构造函数(将执行其成员的复制副本)不同。对每个特殊成员函数统一使用’= default’语法使代码更容易阅读。

再来说一下Deleted Function

在C ++ 11之前,操作符delete 只有一个目的,即释放已动态分配的内存。而C ++ 11标准引入了此操作符的另一种用法,即:禁用成员函数的使用。这是通过附加= delete来完成的; 说明符到该函数声明的结尾。

使用’= delete’说明符禁用其使用的任何成员函数称为expicitly deleted函数。

虽然不限于它们,但这通常是针对隐式函数。以下示例展示了此功能派上用场的一些任务:

禁用拷贝构造函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// copy-constructor using delete operator 
#include <iostream>
using namespace std;

class A {
public:
A(int x): m(x) { }

// Delete the copy constructor
A(const A&) = delete;
// Delete the copy assignment operator
A& operator=(const A&) = delete;
int m;
};

int main() {
A a1(1), a2(2), a3(3);
// Error, the usage of the copy assignment operator is disabled
a1 = a2;
// Error, the usage of the copy constructor is disabled
a3 = A(a2);
return 0;
}

禁用不需要的参数转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// type conversion using delete operator 
#include <iostream>
using namespace std;
class A {
public:
A(int) {}

// Declare the conversion constructor as a deleted function. Without this step,
// even though A(double) isn't defined, the A(int) would accept any double value
// for it's argumentand convert it to an int
A(double) = delete;
};
int main() {
A A1(1);
// Error, conversion from double to class A is disabled.
A A2(100.1);
return 0;
}

请注意,删除的函数是隐式内联的,这一点非常重要。删除的函数定义必须是函数的第一个声明。换句话说,以下方法是将函数声明为已删除的正确方法:

1
2
3
4
5
class C {
public:
C(C& a) = delete;
};

但是以下尝试声明删除函数的方法会产生错误:

1
2
3
4
5
6
7
8
// incorrect syntax of declaring a member function as deleted 
class C {
public:
C();
};

// Error, the deleted definition of function C must be the first declaration of the function.
C::C() = delete;

最后,明确删除函数有什么好处?

删除特殊成员函数提供了一种更简洁的方法来防止编译器生成我们不想要的特殊成员函数。(如“禁用拷贝构造函数”示例中所示)。
删除正常成员函数或非成员函数可防止有问题的类型导致调用非预期函数(如“禁用不需要的参数转换”示例中所示)。