1、什么是构造函数
构造函数的重载:如果没有写任何一个构造函数,系统将为我们提供一个不带参数的默认构造函数。如果我们写了一个带有参数的构造函数,(例如test类,test(int num),这时候已经有了构造函数,系统不会再提供构造函数,这时候如果你这样定义test t;这样会报错,因为找不到没有参数的默认构造函数,你只能test t(10);这样系统才能找到上面定义的构造函数。如果你想要test t;那么你就只能再手动增加一个构造函数 test();)
全局的构造函数先于main函数:
2、析构函数
下面的例子主要体现了构造和析构的顺序(在栈中创建的对象,在生命周期结束的时候会自动调用析构函数,在堆上创建的对象要由程序员显示调用delete释放该对象,同时调用析构函数)
3、转换构造函数
带有一个参数的构造函数,t = 20这一行,里面其实是调用了Test temp(20),然后再将这个temp赋值给t
4、赋值与初始化的区别
头文件和源文件(operator=可以看成一个函数名。重写=运算符)
5、explicit
相当于Test t = 10不能等价于Test t(10);还有Test t; t=10;这样也不行!
6、构造函数初始化列表
7、对象成员及其初始化
对象成员的初始化推荐用初始化列表,初始化的顺序只跟你定义的顺序有关(例如private中的顺序),跟你在构造函数中初始化写的顺序无关。
对象成员,该类如果没有默认构造函数的情况下,只能用初始化列表初始化。
8、const成员、引用成员的初始化
const成员必须在初始化列表中初始化。引用成员也必须在初始化列表中。
9、拷贝构造函数
简单的说,就是用一个对象来初始化另一个对象
注意:参数必须是该类对象的引用。因为如果是值传递的话,在调用这个拷贝构造函数的时候,值传递的时候会分配内存,这样又会去调用拷贝构造函数,这样变成了递归,就永远都出不来,所以必须是引用。
10、拷贝构造函数调用的几种情况
11、深拷贝和浅拷贝
当在构造函数中有动态的分配内存的时候,且这时候要用该A去初始化另B(这里面会调用到默认的拷贝构造函数),默认的拷贝构造函数只是简单的将你的B中的成员指针指向已经分配好内存的A中的数据,这样就变成了两个对象里面的成员指向了同一块内存,这样在析构的时候会析构两次。
例如下面,这样就会报错,因为调用的是默认拷贝构造函数,是浅拷贝,浅拷贝是对值进行逐个赋值,并没有开辟空间,也就是说两个对象里面的成员指向了同一块内存str_,销毁的时候会销毁两次。
这时候就需要自己写一个拷贝构造函数,进行深拷贝。注意:想要深拷贝,就不能用初始化列表的形式进行赋值,因为这样也是浅拷贝,例如下面
深拷贝构造函数如下:
12、对象之间的赋值操作
例如下面这样,因为浅拷贝的原因,一块内存被销毁了两次。
这时候就要提供自己的等号运算符,如下
13、禁止拷贝
要让对象是独一无二的,我们要禁止拷贝。
方法是将拷贝构造函数声明和=运算符声明为私有,并且不提供他们的实现,这样在编译的时候不允许通过。
14、空类默认产生的成员
倒数两个不常见,下面举个例子: