0%

C++ 拷贝构造函数

拷贝构造函数是一种特殊的构造函数,它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象。拷贝构造函数通常用于:

  • 通过使用另一个同类型的对象来初始化新创建的对象。
  • 复制对象把它作为参数传递给函数。
  • 复制对象,并从函数返回这个对象。

拷贝构造函数

定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>
#include <string.h>
#include <stdlib.h>
using namespace std;
class Test
{
public:

Test(int a, int b)
{
x = a;
y = b;
cout << "默认构造函数" << endl;
}
Test(const Test & obj)
{
x = obj.x;
y = obj.y;
cout << "拷贝构造函数" << endl;
}
~Test()
{
cout << x << "," << y << "析构函数调用" << endl;
}
int GetX()
{
return x;
}
int GetY()
{
return y;
}
private:
int x, y;
};



void mainobjplay()
{
Test A(1, 2);
Test B = A; //拷贝构造函数
B = A; //浅拷贝
}

int main()
{
mainobjplay();
return 0;
}

匿名对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

#include "iostream"
using namespace std;


class Location
{
public:
Location( int xx = 0 , int yy = 0 )
{
X = xx ; Y = yy ; cout << "Constructor Object.\n" ;
}
Location( const Location & p ) //拷贝构造函数
{
X = p.X ; Y = p.Y ; cout << "Copy_constructor called." << endl ;
}
~Location()
{
cout << X << "," << Y << " Object destroyed." << endl ;
}
int GetX () { return X ; } int GetY () { return Y ; }
private :
int X , Y ;
} ;


void f ( Location p )
{
cout << "Funtion:" << p.GetX() << "," << p.GetY() << endl ;
}

Location g()
{
Location A(1, 2);
return A;
}

void mainobjplay()
{
/*
Location B; //这两种调用方式差别很大
B = g();
*/
Location B = g(); //将g中的临时变量返回给B,此时b还没有构造,这样就不会调用拷贝构造函数了!
cout << "test" << endl;
}

void main()
{
mainobjplay();
system("pause");
}


如果返回的匿名对象被用来初始化另外一个同类型的类对象,那么匿名对象会直接转成新的对象

深浅拷贝

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <iostream>
#include <string.h>
using namespace std;

class Name
{
public:

Name(const char* pname)
{
size = strlen(pname);
pName = (char *)malloc(size + 1);
strcpy(pName, pname);
}

Name(Name & obj)
{
//用obj对象来初始化自己
pName = (char *)malloc(obj.size + 1);
strcpy(pName, obj.pName);

size = obj.size;
}

~Name()
{
cout << "开始析构" << endl;
if (pName != NULL)
{
free(pName);
pName = NULL;
size = 0;
}
}

private:
char *pName;
int size;
};

void playObj()
{
Name obj1("obj1....");
Name obj2 = obj1;
cout << "操作" << endl;
}


int main()
{
playObj();

return 0;
}

构造函数规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
using namespace std;
#include <string.h>

class Test
{
public:
Test(Test & obj) //如果使用了拷贝构造函数,那么C++编译器则不会提供默认的构造函数
{
a = obj.a;
b = obj.b;
cout << "我是拷贝构造" << endl;
}
Test(int x, int y) //使用了有参构造函数后,c++编译器也不会提供默认的构造函数
{
a = x;
b = y;
}
~Test();

private:
int a;
int b;
};



int main()
{
Test t1; //调用失败

return 0;
}
  • 当类中没有定义任何构造函数的时候,C++编译器会提供无参构造函数和拷贝构造函数
  • 当类中定义了任意非拷贝构造函数(无参、有参),C++编译器不会提供无参构造函数
  • 当类中定义了拷贝构造函数时,C++编译器不会提供无参构造函数
  • 默认拷贝构造函数成员变量简单赋值

构造函数初始化列表

类中有一个数据成员,并且数据成员类中没有提供默认的构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <iostream>
using namespace std;

class A
{
public:
A(int _a,int _b)
{
a = _a;
b = _b;
}

private:
int a;
int b;

};


//构造函数初始化列表

class B
{
public:


B() :Mya(12, 31)
{
;
}
private:
int b1;
A Mya;
};


class CMyClass
{
public:
CMyClass();
CMyClass(int _a,int _b);
~CMyClass();

private:
int a;
int b;
};

CMyClass::CMyClass(int _a, int _b) :a(_a), b(_b)
{
cout << a << endl << b << endl;
}

CMyClass::~CMyClass()
{

}

int main()
{
CMyClass c();
CMyClass(100, 200);
system("pause");
return 0;

}

我们可以尝试给两个类成员进行初始化,中间使用逗号连接;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
using namespace std;

class A
{
public:
A(int _a1)
{
a1 = _a1;
}

private:
int a1;
};




class B
{
public:
B() :mya(12), mya1(100)
{
;
}
B(int x, int y,int z) :mya(y), mya1(z)
{
b1 = x;

}
private:
int b1;
A mya;
A mya1;
};


int main()
{
A a1(10);
B b1(10,20,30);
return 0;
}

匿名对象生命周期

构造函数强化练习

练习01

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
/*
1 C++中提供了初始化列表对成员变量进行初始化
2 使用初始化列表出现原因:
1.必须这样做:
如果我们有一个类成员,它本身是一个类或者是一个结构,而且这个成员它只有一个带参数的构造函数,
而没有默认构造函数,这时要对这个类成员进行初始化,就必须调用这个类成员的带参数的构造函数,
如果没有初始化列表,那么他将无法完成第一步,就会报错。

2、类成员中若有const修饰,必须在对象初始化的时候,给const int m 赋值
当类成员中含有一个const对象时,或者是一个引用时,他们也必须要通过成员初始化列表进行初始化,
因为这两种对象要在声明后马上初始化,而在构造函数中,做的是对他们的赋值,这样是不被允许的。
*/

//总结 构造和析构的调用顺序
#include "iostream"
using namespace std;

class ABC
{
public:
ABC(int a, int b, int c)
{
this->a = a;
this->b = b;
this->c = c;
printf("a:%d,b:%d,c:%d \n", a, b, c);
printf("ABC construct ..\n");
}
~ABC()
{
printf("a:%d,b:%d,c:%d \n", a, b, c);
printf("~ABC() ..\n");
}
protected:
private:
int a;
int b;
int c;
};


class MyD
{
public:
MyD() :abc1(1, 2, 3), abc2(4, 5, 6), m(100)
{
cout << "MyD()" << endl;
}
~MyD()
{
cout << "~MyD()" << endl;
}

protected:
private:
ABC abc1; //c++编译器不知道如何构造abc1
ABC abc2;
const int m;
};


int run()
{
MyD myD;
return 0;
}

int main()
{

run();
system("pause");
return 0;
}

练习02

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
//对象做函数参数
//1 研究拷贝构造
//2 研究构造函数,析构函数的调用顺序

//总结 构造和析构的调用顺序

#include "iostream"
using namespace std;

class ABCD
{ //this()
public:
ABCD(int a, int b, int c)
{
this->a = a;
this->b = b;
this->c = c;
printf("ABCD() construct, a:%d,b:%d,c:%d \n", this->a, this->b, this->c);
}
~ABCD()
{
printf("~ABCD() construct,a:%d,b:%d,c:%d \n", this->a, this->b, this->c);
}
int getA()
{
return this->a;
}
protected:
private:
int a;
int b;
int c;
};


class MyE
{
public:
MyE() :abcd1(1, 2, 3), abcd2(4, 5, 6), m(100)
{
cout << "MyD()" << endl;
}
~MyE()
{
cout << "~MyD()" << endl;
}
MyE(const MyE & obj) :abcd1(7, 8, 9), abcd2(10, 11, 12), m(100)
{
printf("MyD(const MyD & obj)\n");
}

protected:
//private:
public:
ABCD abcd1; //c++编译器不知道如何构造abc1
ABCD abcd2;
const int m;

};

int doThing(MyE mye1)
{
printf("doThing() mye1.abc1.a:%d \n", mye1.abcd1.getA());
return 0;
}

int run2()
{
MyE myE;
doThing(myE);
return 0;
}

//
int run3()
{
printf("run3 start..\n");

ABCD abcd = ABCD(100, 200, 300);
//若直接调用构造函数哪
//想调用构造函数对abc对象进行再复制,可以吗?
//在构造函数里面调用另外一个构造函数,会有什么结果?
//ABCD(400, 500, 600); //临时对象的生命周期
printf("run3 end\n");
return 0;
}

int main()
{
run2();
//run3();
system("pause");
return 0;
}


new和delete

分配基础类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
using namespace std;

int main()
{
int *p1 = (int *)malloc(sizeof(int));
free(p1);

int *p2 = new int;
printf("%d\n", *p2);
delete p2;


int *p3 = new int(100);
delete p3;
return 0;
}

分配数组类型

1
2
3
4
5
6
7
8
9
10
11
int main()
{
int *p = (int *)malloc(10 * sizeof(int)); //int Array[10]
p[0] = 1;
free(p);


int *p2 = new int[10];
p2[0] = 10;
delete [] p2;
}

分配对象类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class Test
{
public:
int x, y;
Test(int mya, int myb)
{
a = mya;
b = myb;
}
int GetA()
{
return a;
}

private:
int a, b;
};


int getTestObj(Test **my)
{
Test *p = new Test(1, 2);
*my = p;
return 0;
}

int FreeObj();

int main()
{
Test t1(10,20);
Test *p = new Test(1, 2);
cout << p->GetA() << endl;
p->x = 10;
p->y = 20;
cout << p->x << endl;
cout << p->y << endl;
getTestObj(&p);
delete p;
return 0;
}

对象管理模型

C++中类对象的成员变量和成员函数是分开存储的

  • 成员变量
    • 普通成员变量:存储与对象中,与struct变量有相同的内存布局和字节对齐方式
    • 静态成员变量:存储与全局数据区中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>
using namespace std;



class Test
{
public:
int i;
int j;
int k;
private:

};


class Test01
{
public:
int i;
int j;
int k;
static int l;
private:

};


struct Test02
{
int i;
int j;
int k;
static int l;
};


int main()
{

printf("test size = %d\n", sizeof(Test)); //12
printf("test01 size = %d\n", sizeof(Test01)); //12
printf("test02 size = %d\n", sizeof(Test02)); //12
system("pause");
return 0;
}