[TOC]

文章参考:https://www.cnblogs.com/lsgxeva/p/7787438.html

概述

C++11 类默认函数的控制:”=default” 和 “=delete”函数

C++ 的类有四类特殊成员函数,它们分别是:默认构造函数、析构函数、拷贝构造函数以及拷贝赋值运算符。

这些类的特殊成员函数负责创建、初始化、销毁,或者拷贝类的对象。

如果程序员没有显式地为一个类定义某个特殊成员函数,而又需要用到该特殊成员函数时,则编译器会隐式的为这个类生成一个默认的特殊成员函数。

C++11 标准引入了一个新特性:”=default”函数。程序员只需在函数声明后加上“=default;”,就可将该函数声明为 “=default”函数,编译器将为显式声明的 “=default”函数自动生成函数体。

override关键字

override关键字主要在声明类的成员函数时使用,它的作用就是告知程序员和编译器这个函数是重写了父类的虚函数,一方面代码的阅读者看到这个关键字标识就知道这是一个重写的函数;另一方面也给编译器进行检测:如果这个函数实际上没有重写父类的虚函数则会报错:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class A
{
public:
virtual void func1();
void func2();
};

class B:public A
{
public:
//A的func1是虚函数,可以编译通过
void func1() override;
//A的func2不是虚函数,编译器会报错
void func2() override;
};

default关键字

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

至于另一个关键字default,它是在强行指定某个构造函数为默认构造函数。众所周知,当一个类声明了一个带参数构造函数后,编译器便不会再帮助该类生成默认构造函数,此时可以通过=default显式将某个构造函数定义为默认构造函数(当然这个函数的参数要符合规范,也不需要定义的)。其实不止默认构造函数,也可以以此定义默认拷贝构造函数和析构函数,对每个特殊成员函数统一使用=default语法也使得使代码更容易阅读。

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

下面的代码通过default定义了A的默认构造函数和默认拷贝构造函数,也包括默认析构函数:

1
2
3
4
5
6
7
class A
{
public:
A() = default;
A(A&) = default;
~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;
}

delete关键字

delete关键字,在C++11之前,它只是用于释放内存空间。C++11为它增加了新的意义:禁用某个类的成员函数。比如我们如果不想让某个类对象被拷贝,可以通过delete语法修饰它的拷贝构造函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class A
{
public:
A() = default;
A(const A&) = delete;
~A() = default;
};

int main()
{
A a;
A b = a; //编译器会报错,因为此时a的拷贝构造函数已经被禁用了
return 0;
}

delete还有一种常用的用法就是禁用某种类型转换的构造函数,使得无法将类转换为某种特定类型。

1
2
3
4
5
6
7
8
9
10
11
12
class A 
{
public:
A(int) {}
A(double) = delete;
};

int main() {
A A1(1);
A A2(0.1);//编译器会报错,因为此时a从double构造的函数被禁用了
return 0;
}

最后说一句,delete关键字不仅可以用来修饰成员函数,也可以修饰非成员函数。比如说,我们希望一个函数只接受float类型的参数,那我们可以这样设计:

1
2
3
void func(float) {}
void func(double)=delete;
void func(int)=delete;