1.2つの特別なコンストラクタ
- 引数なしのコンストラクタは引数を持たないコンストラクタ 説明するために:引数なしのコンストラクタは、非常に単純なように見えるが、それは特にであることが存在している必要があります。私たちはクラスを使用したいので、あなたがオブジェクトを作成する必要があります。オブジェクトを作成することは、必ずしもコンストラクタを呼び出す必要とします。 注:クラスが定義されていないコンストラクタは、コンパイラ時にデフォルトで提供引数なしのコンストラクタ、および関数本体は空です。クラスがコンストラクタを持っていない時に特別な注意を払う必要があり、コンパイラが提供されます、または提供することはありません。 -コピーコンストラクタ コンストラクタパラメータのconst CLASS_NAME& (コンストラクタを分析するコピーコンストラクタに基づくものではない:1、CONST 2、オブジェクトの現在のクラスを指す。)であれば、このようなパラメータとは、それがなければならず、コンストラクタ関数に表示されますこれは、コピーコンストラクタアップです。
クラスはコピーコンストラクタを定義されていない場合は、コンパイラは、単にメンバ変数のデフォルトの値をコピーし、コピーコンストラクタを提供します。
1つの#include <stdio.hの>
2
3 級試験
4 {
5 プライベート:
6 INT I。
7 int型J;
8 公共:
9 INT GETI()
10 {
11 リターンiは、
12 }
13 INT getJ()
14 {
15 リターンJ。
16 }
17 / * テスト(CONSTテスト&T)
18 {
19 、I = TI。
20 J = TJ;
21 }
22 試験()
23 {
24 } * /
25 }。
26
27 のint main()の
28 {
29 テストT1。
30 テストT2 = T1。
31
32 のprintf(" t1.i =%dの、t1.j =%d個の\ n " 、t1.getI()、t1.getJ())。
33 のprintf(" t2.i =%dの、t2.j =%d個の\ n " 、t2.getI()、t2.getJ())。
34
35 戻り 0 ;
36 }
上記の例では、一度定義
Test(const Test& t) { i = t.i; j = t.j; }
那么Test t1;就会出错。为什么?
因为找不到一个Test()的构造函数。
问题:不是编译器会默认提供一个无参构造函数吗?
一定要注意,编译器提供默认构造函数的前提,就是类中没有构造函数,一旦拥有,编译器就不再提供。
同样,如果定义了
Test()
{
}
Test t2 = t1,也会出错。原因和上面一样。
呈现一个经典面试题,下面的这个类,它里面有什么东西?
class T
{
};
它里面至少有一个无参构造函数,是编译器提供的。
2. 拷贝构造函数的意义
-兼容C语言的初始化方式
例如:int i =2; int j = i;
Test t1; Test t2 = t1;
-初始化行为能够符合预期的逻辑
-浅拷贝
拷贝后对象的物理状态相同
-深拷贝
拷贝后对象的逻辑状态相同
编译器提供的拷贝构造函数只进行浅拷贝。
1 #include <stdio.h>
2
3 class Test
4 {
5 private:
6 int i;
7 int j;
8 int* p;
9 public:
10 int getI()
11 {
12 return i;
13 }
14 int getJ()
15 {
16 return j;
17 }
18 int* getP()
19 {
20 return p;
21 }30 Test(int v)
31 {
32 i = 1;
33 j = 2;
34 p = new int;
35
36 *p = v;
37 }42 };
43
44 int main()
45 {
46 Test t1(3);
47 Test t2(t1);
48
49 printf("t1.i = %d, t1.j = %d, *t1.p = %p\n", t1.getI(), t1.getJ(), t1.getP());
50 printf("t2.i = %d, t2.j = %d, *t2.p = %p\n", t2.getI(), t2.getJ(), t2.getP());54
55 return 0;
56 }
上面的这个程序,编译会顺利通过。并且你会看到一个现象,t1对象的p和t2对象的p指向了同一段堆空间。你是不是想,这是肯定的啊。因为我就是用t1初始化t2,这正是我想要的结果。但是根据经验,p是在堆上生成的,当我们不用的时候,需要将其释放掉。如下面的代码所示:
1 #include <stdio.h>
2
3 class Test
4 {
5 private:
6 int i;
7 int j;
8 int* p;
9 public:
10 int getI()
11 {
12 return i;
13 }
14 int getJ()
15 {
16 return j;
17 }
18 int* getP()
19 {
20 return p;
21 }30 Test(int v)
31 {
32 i = 1;
33 j = 2;
34 p = new int;
35
36 *p = v;
37 }
38 void free()
39 {
40 delete p;
41 }
42 };
43
44 int main()
45 {
46 Test t1(3);
47 Test t2(t1);
48
49 printf("t1.i = %d, t1.j = %d, *t1.p = %p\n", t1.getI(), t1.getJ(), t1.getP());
50 printf("t2.i = %d, t2.j = %d, *t2.p = %p\n", t2.getI(), t2.getJ(), t2.getP());
51
52 t1.free();
53 t2.free();
54
55 return 0;
56 }
编译就会出错,因为我们释放了两次相同堆空间中的内存。t1中的p和t2中的p指向了同一段堆空间。
如何解决这个问题?
应该手工来提供一个拷贝构造函数
1 #include <stdio.h>
2
3 class Test
4 {
5 private:
6 int i;
7 int j;
8 int* p;
9 public:
10 int getI()
11 {
12 return i;
13 }
14 int getJ()
15 {
16 return j;
17 }
18 int* getP()
19 {
20 return p;
21 }
22 Test(const Test& t)
23 {
24 i = t.i; //首先是值的复制
25 j = t.j;
26 p = new int;
27
28 *p = *t.p; //p的值就不能直接复制了,需要重新到堆空间中申请。申请完之后,将t1对象中p空间中的值拿出来,放到新申请的堆空间中去。
29 }
30 Test(int v)
31 {
32 i = 1;
33 j = 2;
34 p = new int;
35
36 *p = v;
37 }
38 void free()
39 {
40 delete p;
41 }
42 };
43
44 int main()
45 {
46 Test t1(3);
47 Test t2(t1);
48
49 printf("t1.i = %d, t1.j = %d, *t1.p = %p\n", t1.getI(), t1.getJ(), t1.getP());
50 printf("t2.i = %d, t2.j = %d, *t2.p = %p\n", t2.getI(), t2.getJ(), t2.getP());
51
52 t1.free();
53 t2.free();
54
55 return 0;
56 }