最头疼的来啦,复制构造函数,看着就他妈头疼,研究好几天还是没明白啥复制构造函数。简单的总结一下哈,省着过一会又他妈忘了刚才看懂的。
复制构造函数有以下三种情况会调用:
1. 同类的一个对象初始化该类的另一个对象时使用
2. 当函数的形参是类的对象,调用函数实行实参与形参得的另一个对象时使用。
3. 当函数的返回值是类的对象,函数执行结束返回调用者时使用。
是不是有点熟悉,对,引用时就是这三个方面才使用
复制构造函数好像最主要的作用就是这三个。实践才是检验真理的唯一标准,接下来用几个实验验证一下吧。
一,对象为另一个对象进行初始化
1) #include<iostream>
2) using namespace std;
3) class A{
4)
5) int a,b;
6) public:
7) A()
8) {
9) a=0;
10) b=0;
11) }
12) A(int c,int d)
13) {
14) a=c;
15) b=d;
16) }
17)
18)
19)
20) void show()
21) {
22) cout<<a<<' '<<b<<endl;
23) }
24)
25) };
26)
27) int main()
28) {
29) A a1,a2(5,6),a3(a2),a4;
30) a4=a2;
31)
32) a1.show();
33)
34) a2.show();
35) a3.show();
36) a4.show();
37) return 0;
38) }
二,当函数传入的是一个对象时
此时为默认的复制构造函数,可以看出,可以进行对第二个新对象的赋值。看下面代码(偷来的,比较好理解,好吧,我懒,嘻嘻)
1) #include<iostream>
2) using namespace std;
3) class CExample
4) {
5) private:
6) int a;
7)
8) public:
9) //构造函数
10) CExample(int b)
11) {
12) a = b;
13) cout<<"creat:"<<a<<endl;
14) }
15)
16) //拷贝构造
17)
18)
19)
20) ~CExample()
21) {
22) cout<< "delete:"<<a<<endl;
23) }
24)
25) void Show ()
26) {
27) cout<<a<<endl;
28) }
29) };
30)
31) //全局函数,传入的是对象
32) void g_Fun(CExample B)
33) {
34) cout<<"test"<<endl;
35) }
36)
37) int main()
38) {
39) CExample test(1);
40)
41)
42) //传入对象
43) g_Fun(test);
44)
45) return 0;
}
此代码中也是默认的复制构造函数执行如下
下面我们人为加入复制构造函数代码
1) #include<iostream>
2) using namespace std;
3) class CExample
4) {
5) private:
6) int a;
7)
8) public:
9) //构造函数
10) CExample(int b)
11) {
12) a = b;
13) cout<<"creat:"<<a<<endl;
14) }
15)
16) //拷贝构造
17) CExample(const CExample& C)
18) {
19) a = C.a;
20) cout<<"copy"<<endl;
21) }
22)
23) //析构函数
24) ~CExample()
25) {
26) cout<< "delete:"<<a<<endl;
27) }
28)
29) void Show ()
30) {
31) cout<<a<<endl;
32) }
33) };
34)
35) //全局函数,传入的是对象
36) void g_Fun(CExample C)
37) {
38) cout<<"test"<<endl;
39) }
40)
41) int main()
42) {
43) CExample test(1);
44) //传入对象
45) g_Fun(test);
46)
47) return 0;
48) }
运行结果为
看到我们的复制构造函数多了一个copy对吧,其实默认的复制构造函数就是给我们每个数据赋值但如果我们自己定义就不同了,接下来这几句很重要(抄来的,嘻嘻)
调用g_Fun()时,会产生以下几个重要步骤:
(1).test对象传入形参时,会先会产生一个临时变量,就叫 C 吧。
(2).然后调用拷贝构造函数把test的值给C。 整个这两个步骤有点像:CExampleC(test);
(3).等g_Fun()执行完后, 析构掉 C 对象。
记住了吗
三,当返回值是一个类时。
接下来是第三种,当返回的是一个类时,如代码
#include<iostream>
usingnamespace std;
classCExample
{
private:
int a;
public:
//构造函数
CExample(int b)
{
a = b;
}
//拷贝构造
CExample(const CExample& C)
{
a = C.a;
cout<<"copy"<<endl;
}
void Show ()
{
cout<<a<<endl;
}
~CExample()
{
cout<<"delet"<<endl;
}
};
//全局函数
CExampleg_Fun()
{
CExample temp(0);
return temp;
}
intmain()
{
g_Fun();
return 0;
}
运行为
接下来几句也很重要
当g_Fun()函数执行到return时,会产生以下几个重要步骤:
(1). 先会产生一个临时变量,就叫XXXX吧。
(2). 然后调用拷贝构造函数把temp的值给XXXX。整个这两个步骤有点像:CExampleXXXX(temp);
(3). 在函数执行到最后先析构temp局部变量。
(4). 等g_Fun()执行完后再析构掉XXXX对象。
由于第一种我没写太复杂(没有析构函数和复制构造函数)可能没啥用第一种情况,好好看第二种吧。嗯,yes。
然后其实吧我们初学者不用写复制构造函数就可以了,大部分就能完成,但是呢好像这里有一些就是勇敢默认的复制函数的一些弊端,不过who care??我弄明白这是个啥东西就不错了。还是copy过来吧
· 由于并非所有的对象都会使用拷贝构造函数和赋值函数,程序员可能对这两个函数有些轻视。请先记住以下的警告,在阅读正文时就会多心: 1.如果不主动编写拷贝构造函数和赋值函数,编译器将以“位拷贝”的方式自动生成缺省的函数。倘若类中含有指针变量,那么这两个缺省的函数就隐含了错误。以类String的两个对象a,b为例,假设a.m_data的内容为“hello”,b.m_data的内容为“world”。 现将a赋给b,缺省赋值函数的“位拷贝”意味着执行b.m_data = a.m_data。这将造成三个错误:一是b.m_data原有的内存没被释放,造成内存泄露;二是b.m_data和a.m_data指向同一块内存,a或b任何一方变动都会影响另一方;三是在对象被析构时,m_data被释放了两次。即:当含有指针时,如果调用默认的拷贝拷贝构造函数(赋值运算符),这个时候进行的浅拷贝(赋值),或者是影子拷贝,会使2个指针指向同一个内存区域,析构的时候就会出现同一个内存资源被释放2次的错误。对象存在资源但复制过程并未复制资源的情况视为浅拷贝。
最后给个链接这才是大神写的文章吗下边
https://blog.csdn.net/qq_16583687/article/details/74909903
谢谢我吧