在C++中,声明自定义的类型之后,编译器会默认生成一些成员函数,这些函数被称为默认函数。其中包括
(1)(默认)构造函数
(2)拷贝(复制)构造函数
(3)拷贝(复制)赋值运算符
(4)移动构造函数
(5)移动赋值运算符
(6)析构函数
另外,编译器还会默认生成一些操作符函数,包括
(7)operator ,
(8)operator &
(9)operator &&
(10)operator *
(11)operator ->
(12)operator ->*
(13)operator new
(14)operator delete
【1】显式缺省函数(=default)
如果类设计者又实现了这些函数的自定义版本后,编译器就不会去生成默认版本。
大多数时候,我们需要声明带参数的构造函数,此时就不会生成默认构造函数,这样会导致类不再是POD类型(可参见随笔《C++11 POD类型》),从而影响类的优化:
1 #include <iostream>
2 using namespace std;
3
4 class Test
5 {
6 public:
7 Test(int i) : data(i) {}
8
9 private:
10 int data;
11 };
12
13 int main()
14 {
15 std::cout << std::is_pod<Test>::value << std::endl; // 0
16 }
C++11中提供了新的机制来控制默认函数生成来避免这个问题:声明时在函数末尾加上”= default”来显式地指示编译器去生成该函数的默认版本,这样就保证了类还是POD类型:
1 #include <iostream>
2 using namespace std;
3
4 class Test
5 {
6 public:
7 Test() = default; // 显式指定缺省函数
8 Test(int i) : data(i) {}
9
10 private:
11 int data;
12 };
13
14 int main()
15 {
16 std::cout << std::is_pod<Test>::value << std::endl; // 1
17 }
【2】显式删除函数(=delete)
另一方面,有时候可能需要限制一些默认函数的生成。
例如:需要禁止拷贝构造函数的使用。以前通过把拷贝构造函数声明为private访问权限,这样一旦使用编译器就会报错。
而在C++11中,只要在函数的定义或者声明后面加上”= delete”就能实现这样的效果(相比较,这种方式不容易犯错,且更容易理解):
1 #include <iostream>
2 using namespace std;
3
4 class Test
5 {
6 public:
7 Test() = default; // 显式指定缺省函数
8 Test(int i) : data(i) {}
9 Test(const Test& t) = delete; // 显式删除拷贝构造函数
10
11 private:
12 int data;
13 };
14
15 int main()
16 {
17 Test objT1;
18 // Test objT2(objT1); // 无法通过编译
19 }
【3】其他应用
(1)= default和= delete 能够更加精准的控制类的默认函数版本。其中,= default同样也能在类外的定义中修饰成员函数:
1 class Example
2 {
3 public:
4 Example() = default;
5 Example(const Example&);
6
7 private:
8 int data;
9 };
10
11 Example::Example(const Example& ex) = default;
这样的好处是,能够为一个类实现多个版本,只要我们在头文件里声明同样的函数,而在不同的cpp文件中用不同的方法实现,当选择不同的cpp编译时产生的版本就不同。
(2)关于= delete,它不仅局限于限制生成默认函数,还能避免编译器做一些不必要的隐式数据转换:
隐式转换示例:
1 class Example
2 {
3 public:
4 Example(int i) {}
5 };
6
7
8 int main()
9 {
10 Example ex(1);
11 Example ex1('a'); // 编译成功,char会隐式装换成int型
12 }
有时候我们不想要这种隐式转换:
1 class Example
2 {
3 public:
4 Example(int i) {}
5 Example(char c) = delete;
6 };
7
8
9 int main()
10 {
11 Example ex(1);
12// Example ex1('a'); // 无法通过编译
13 }
这个方法也能用于普通函数:
1 void func(int i) {}
2 void func(char c) = delete;
3
4 int main()
5 {
6 func(1);
7// func('a'); // 编译失败
8 }
另外,还有很多使用场景,例如,显式删除new操作符来避免在堆上分配对象、显式删除析构函数用于构建单例模式等等。
总之,default只能用于6个特殊成员函数,但delete可用于任何成员函数。
good good study, day day up.
顺序 选择 循环 总结
原文链接: https://www.cnblogs.com/Braveliu/p/12247471.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/192574
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!