一、对象的拷贝
拷贝和复制是一个意思,对计算机来说就是利用已经存在的数据创建出一份新的和原有数据一模一样的数据。在C++中,拷贝是指用已经存在的对象创建出一个新的对象。严格来说,对象的创建包括两个阶段,首先要分配内存空间,然后再进行初始化。
- 分配内存空间就是在,就是在堆、栈或者全局数据区留出足够的字节空间,它所包含的数据一般是零或者随机值,没有什么实际意义。
- 初始化就是首次对留出的这段字节空间赋值,让里面的数据具有实际意义。这里一定得是首次赋值,再次赋值就不是初始化了。
这里的拷贝是在初始化阶段进行的,就是用其它的对象的数据来初始化新对象的内存。
二、以拷贝方式来初始化对象的例子
#include<iostream>
#include<sttring>
using namespace std;
void func(string str)
{
cout<<str<<endl;
}
int main()
{
string str1 = "Hello String";
string str2(str1);
string str3 = str1;
string str4 = str1 + " " +str2;
func(str1);
cout<<str1<<endl<<str2<<endl<<str3<<endl<<str4<<endl;
return 0;
}
/*
运行结果:
Hello String
Hello String
Hello String
Hello String
Hello String Hello String
*/
上述例子中,str1,str3,str3,str4以及 func() 的形参 str, 都是使用拷贝的方式来初始化的。
- 对于 str1,表面上看起来是将一个字符串直接赋值给了 str1,实际上在内部进行了类型转换,将 const char * 类型转换为 string 类型后才赋值的。
- 对于 func() 的形参 str,其实在定义时就为它分配了内存,但是此时并没有初始化,只有等到调用 func() 时,才会将其它对象的数据拷贝给 str 以完成初始化。
当以拷贝的方式初始化一个对象时,会调用一个特殊的构造函数,就是拷贝构造函数。
三、拷贝构造函数的定义及使用
#include<iostream>
#include<string>
using namespace std;
class Student
{
public:
Student(string name="" ,int age=0); //普通构造函数
Student(const Student &stu); //拷贝构造函数(声明)
~Student();
void display();
private:
string m_name;
int m_age;
};
Student::Student(string name, int age )
{
m_name = name;
m_age = age;
}
Student::Student(const Student &stu) //拷贝构造函数(定义)
{
this->m_name = stu.m_name;
this->m_age = stu.m_age;
cout << "Copy constructor was called." << endl;
}
Student::~Student()
{
}
void Student::display()
{
cout << m_name << " " << m_age << endl;
}
int main()
{
Student stu1("Student", 13);
Student stu2 = stu1; //调用拷贝构造函数
Student stu3(stu1); //调用拷贝构造函数
stu1.display();
stu2.display();
stu3.display();
return 0;
}
/*
输出:
Copy constructor was called.
Copy constructor was called.
Student 13
Student 13
Student 13
*/
1. 拷贝构造函数的参数为什么是当前类的引用?
如果拷贝构造函数的参数不是当前类的引用,而是当前类的对象,那么在调用拷贝构造函数时,会将另外一个对象直接传递给形参,这本身就是一次拷贝,会再次调用拷贝构造函数,然后又将一个对象直接传递给了形参,将继续调用拷贝构造函数……这个过程会一直持续下去,没有尽头,陷入死循环。
2. 为什么是const 引用?
拷贝构造函数的目的是用其它对象的数据来初始化当前对象,并没有期望更改其它对象的数据,添加 const 限制后,这个含义更加明确了。
另外一个原因是,添加 const 限制后,可以将 const 对象和非 const 对象传递给形参了,因为非 const 类型可以转换为 const 类型。如果没有 const 限制,就不能将 const 对象传递给形参,因为 const 类型不能转换为非 const 类型,这就意味着,不能使用 const 对象来初始化当前对象了。
四、默认拷贝构造函数
如果程序员没有显式地定义拷贝构造函数,那么编译器会自动生成一个默认的拷贝构造函数。这个默认的拷贝构造函数很简单,就是使用“老对象”的成员变量对“新对象”的成员变量进行一一赋值,和上面 Student 类的拷贝构造函数非常类似。
对于简单的类,默认拷贝构造函数一般是够用的,我们也没有必要再显式地定义一个功能类似的拷贝构造函数。但是当类持有其它资源时,如动态分配的内存、打开的文件、指向其他数据的指针、网络连接等,默认拷贝构造函数就不能拷贝这些资源,我们必须显式地定义拷贝构造函数,以完整地拷贝对象的所有数据 。
|
请发表评论