一.拷贝构造函数的作用
拷贝构造函数本质上就是将已存在的对象拷贝给正在创建的相同类的对象。
二.拷贝构造函数的形式
一般是不需要专门定义拷贝构造函数的,因为编译器在检测到没有定义拷贝构造函数的时候,就会自己定义一个缺省的拷贝构造函数。
这个拷贝构造函数对于基本成员变量,是直接复制
对于类类型的成员变量,则会调用相对应的拷贝构造函数。
#include<iostream>
using namespace std;
class A
{
int m_a;
public:
A(int a);
void print();
};
void A:: print()
{
cout << m_a << endl;
}
A::A(int a)
{
m_a = a;
}
int main()
{
A a1(5);
a1.print(); 5
A a2(a1);
a2.print(); 5
return 0;
}
这是一个拷贝构造函数的定义:
类名(const 类名 & r_m)
{
}
#include<iostream>
using namespace std;
class A
{
int m_a;
public:
A(int a); 构造函数
A(const A& c); 拷贝构造函数
void print();
};
void A:: print()
{
cout << m_a << endl;
}
A::A(const A& c)
{
this->m_a = c.m_a;
}
A::A(int a)
{
m_a = a;
}
int main()
{
A a1(5);
a1.print();
A a2(a1);
a2.print();
return 0;
}
以上是一个拷贝构造函数的使用,现在来了解一下为什么要这样写:
为什么要使用引用传递?
若不使用引用传递,则是一个值传递,而形参则是需要创建一个临时变量,拷贝实参,这个过程就需要使用拷贝构造函数!
但在这种拷贝构造函数定义下,你需要值传递,值传递需要使用拷贝构造函数,就无限循环下去了。
使用引用传参,那么形参就是实参的一个别名,两者共用一个内存空间,不需要使用拷贝构造函数。
为什么要使用 const 修饰
在拷贝构造函数中不应该修改原对象的数据,
class A
{
int m_num;
public:
A(const A c) 错误拷贝构造函数
{
m_num = c.m_num;
}
A(int num) 构造函数
{
m_num = num;
}
}
int main()
{
A a(10);
A a1(a);
}
上文说过,一般来说,我们不需要主动定义拷贝构造函数,编译器会提供拷贝构造函数,但是在一些特定的情况下,我们需要主动定义。
深拷贝和浅拷贝
一般来说,只有基本类型成员变量的对象,可以使用系统提供的拷贝构造函数,因为其是一对一的复制。这种成为浅拷贝。
而当存在指针类型的成员变量的时候,就需要深拷贝函数,因为若是浅拷贝,正在创建的对象的指针变量和被拷贝的对象的指针就都包含同一块地址,在两者的作用域结束后,就会调用析构函数,两次析构函数都释放同一块空间,就会造成“double free”问题。
class A
{
public:
A(double height = 0, int age = 0, const string&name = "") :m_height(height),
m_p_age(new int(age)), m_name(name)
{
cout << "构造" << endl;
}
~A()
{
cout << "析构" << endl;
delete m_p_age;
}
A(const A& that) //深拷贝
{
cout << "拷贝构造" << endl;
m_height = that.m_height;
m_p_age = new int(*that.m_p_age);
m_name = that.m_name;
}
double m_height;
int* m_p_age;
string m_name;
}