C++11 =default,=delete

发布时间:2024年01月22日

C++11 =default,=delete

1. 简介

=default 和 =delete 大部分情况下是用在构造函数(ctor)、析构函数、拷贝构造和拷贝赋值函数(这四种函数被称为 Big-Three)中。

如果自己已经有定义了一个 ctor ,那么编译器就不会在给你一个 default ctor。如果你强制加上 =default,就可以重新获得并使用 default ctor。default ctor 就是编译器给的默认的构造函数。如果你没有显式写出构造函数,我们常说有默认的构造函数,其实指的就是这一个。

单纯的 default ctor 没什么用,只是一个空函数,因为编译器不知道你要做什么。但如果有继承关系的话,这个 default ctor 就很有用。因为如果这个类是有继承其他父类的话,且 ctor 是 default ctor 的话,当调用到该类时,如果使用的是 default ctor ,这个 default ctor 里面会帮你调用父类的 ctor。也就是编译器背后会给你加上代码。

·· 在这里插入图片描述

Big-Three 加上右值引用的构造函数和它的拷贝赋值就是 Big-Five。

2. 示例

如果有一个类 Foo,类中有一个成员变量 _i。

Foo(int i):_i(i){}
Foo() = default;

上面这样写是可以编译通过的,因为构造函数是可以多个的,也就是可以重载,所以上面两个可以并存。

Foo(const Foo& x):_i(x._i){}
//有了上面的,则下面这两个都会报错
Foo(const Foo&) = default;   //报错
Foo(const Foo&) = delete;    //报错

拷贝构造函数只能有一个,不能多个。否则会报如下的错误:
在这里插入图片描述

拷贝赋值函数元素同理的。
在这里插入图片描述

析构函数也是同理,只能有一个析构函数。
在这里插入图片描述

你会想普通函数可以吗?例如下面这样子
在这里插入图片描述
当你在类中定义如上两个成员函数时,使用 =default 会报错,因为编译器不知道你默认是要干嘛的,而且这样写没有意义。而使用 =delete 是可以的,但是就是有点奇怪,因为你如果不要这个函数,就干脆不写出来就可以了。

看到这里,可以总结出:delete 可以用在任意函数上

而这里需要注意的是,=0 只能用在虚函数(virtual)身上。如果你写 void func2() = 0; 就会报错。

3. 当我们写一个空的类,里面就真的是空的吗

在这里插入图片描述

当我们写了一个这样的类 class Empty{}; 编译器会默认给我们一个 Big-Three 的类。也就是这个类里面会有默认的构造函数、拷贝构造函数、析构函数和拷贝赋值函数。C++11之后,就是 Big-Five,会多一个移动构造函数(也就是参数是右值引用的)。你可以注意到,这个类默认给的这些函数都是 public 且是 inline。

而你会问编译器这样有什么用?它跟上面讲过的同理,就是为了有继承关系的时候,编译器可以在这些函数中藏一些“幕后操作”的代码,例如一个类B 继承了类 A,B只是如上面一样,是一条语句,也就是一个空类,编译器会帮 B 在 B 类中的 Big-Five 函数增加代码,以便 B 可以正确地生成和释放,会帮助 B 调用 A的构造函数和析构函数。

4. 到底什么样的类需要自己定义 Big-Three

一个类中只要带有指针的成员你就需要自己定义类,自己写出 Big-Three,不能使用默认的。如果一个类中没有指针成员就可以断定大概率不用自己写 Big-Three,使用默认的类就好。

带有指针的话,就有深拷贝和浅拷贝;如果只是单纯地把指针,四个字节拷贝过去,也就是两个指针指向同一块内存,这种就叫浅拷贝。深拷贝则是,指针所指向的那一块内存也要拷贝过去。

例如复数的类,就是可以直接使用默认的 Big-Three。
在这里插入图片描述
复数只有实部、虚部,没有指针,所以拷贝构造和拷贝赋值只是将数据忠实地拷贝过去,所以不需要自己去写一套,可以直接用编译器默认给的。

而 string 类,它的内部就有一个指针,指向一块放字符串的内存。所以 string 类是需要有显式的 Big-Three 的。

5. No-Copy

在这里插入图片描述

如果不像一个类可以被拷贝,就可以像上面一样。把拷贝构造和拷贝赋值设置为 delete。

6. No-Dtor(没有析构函数)

在这里插入图片描述

如果我们不要析构函数的话,要显式地写出来,赋值为 delete。delete 可以运用于任何成员函数,但是用于析构函数上时,后果自负。因为对象总有离开作用域的时候,但是调用不了析构函数会报错,如上图所示。

7. Private-Copy

在这里插入图片描述

把拷贝构造和拷贝复制放到私有里面,就不允许一些普通的对象可以调用,但允许被友元或者成员函数调用。

文章来源:https://blog.csdn.net/weixin_45604295/article/details/135437497
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。