以下内容牵扯到了一点点计数器的知识!
什么是拷贝构造函数
是区别于不同类型的对象来说的一种复制,相同类型的类对象是通过拷贝构造来进行复制的。简单来说,系统会分配另一个内存呢来完成copy!
拷贝构造函数的调用
1.当调用函数的参数为类的对象
#include<iostream>
using namespace std;
class CExample
{
private:
int a;
public:
CExample(int b)
{
a=b;
printf("constructor is called\n");
}
CExample(const CExample & c)
{
a=c.a;
printf("copy constructor is called\n");
}
~CExample()
{
cout<<"destructor is called\n";
}
void Show()
{
cout<<a<<endl;
}
};
void g_fun(CExample c)
{
cout<<"g_func"<<endl;
}
int main()
{
CExample A(100);
CExample B=A;
B.Show();
g_fun(A);
return 0;
}
在main函数调用g_fun()时,会发生的几个步骤:
** 1.A对象传入形参时,会先产生一个临时变量C
2.之后,会调用拷贝构造函数把A的值给C,这俩步骤类似于:CExample C(A);
3.g_fun()执行完之后,就会析构雕对象C;**
运行结果:
constructor is called
copy constructor is called
100
copy constructor is called
g_func()
destructor is called
destructor is called
destructor is called
2.函数的返回值为类:
#include<iostream>
using namespace std;
class CExample
{
private:
int a;
public:
//构造函数
CExample(int b)
{
a=b;
printf("constructor is called\n");
}
//拷贝构造函数
CExample(const CExample & c)
{
a=c.a;
printf("copy constructor is called\n");
}
//析构函数
~CExample()
{
cout<<"destructor is called\n";
}
void Show()
{
cout<<a<<endl;
}
};
CExample g_fun()
{
CExample temp(0);
return temp;
}
int main()
{
g_fun();
return 0;
}
在g_fun()函数执行到return时,产生的几个步骤:
** 1.首先会产生一个临时变量T
2.然后调用拷贝构造函数把temp的值给T,这俩步骤类似于 CExample T(temp);
3.因为temp是局部变量,所以在函数执行到对后时,先析构temp
4整个g_fun()函数都执行结束后,再析构T**
深拷贝和浅拷贝
总的前提:在出现类的等号赋值时,就会出现拷贝!在用户没有定义拷贝构造函数的时候,系统会有一个默认的拷贝函数——浅拷贝
当数据中有指针时,如果采用浅拷贝,俩个类的俩个指针都会指向同一个地址,当对象快death时会调用俩次析构函数,导致指针悬垂
而深拷贝可以在堆内存中另外申请空间来储存数据,从而解决指针悬垂!有指针,必须深拷贝
深拷贝:
#include<iostream>
#include<assert.h>
using namespace std;
class Rect
{
public:
Rect()
{
p=new int(100);
}
Rect(const Rect& r)
{
width=r.width;
height=r.height;
p=new int(100);
*p=*(r.p);
}
~Rect()
{
assert(p!=NULL);
delete p;
}
private:
int width;
int height;
int *p;
};
int main()
{
Rect rect1;
Rect rect2(rect1);
return 0;
}
深拷贝需要重新动态分配空间
tips:
我们发现对象的复制大多在进行“值传递”时发生,这里有一个小技巧可以防止按值传递——**声明一个私有拷贝构造函数。**甚至不必去定义这个拷贝构造函数,这样因为拷贝构造函数是私有的,如果用户试图按值传递或函数返回该类对象,将得到一个编译错误,从而可以避免按值传递或返回对象。