使用场景
拷贝构造函数是用另一个对象构造当前对象的时候执行的。
拷贝构造函数就是函数名是当前类的名字,参数为当前类的另一个对象的函数
编译器合成的拷贝构造函数
如果你没有定义拷贝构造函数,编译器会替你合成一个。
绝大多数情况下,使用编译器合成的版本即可。
除非需要手动进行复制控制
自己定义拷贝构造函数
class Student
{
public:
//拷贝构造函数就是函数名是当前类的名字,参数为当前类的另一个对象的函数
Student(const Student& copy_from);//声明拷贝构造函数
string m_name;
int m_age;
};
//定义拷贝构造函数
Student::Student(const Student& copy_from)
:m_name(copy_from.m_name),m_age(copy_from.m_age)
{
}
有了上面自定义的拷贝构造函数,当再次发生对象拷贝构造的时候就会执行上面的拷贝构造函数(虽然在大多数时候你都不必大费周折亲自写这样一个函数,使用编译器合成的版本即可)。
何时执行拷贝构造函数
有下面三种情况:
1 用已有对象构造新对象的时候
Student stu;//先定义一个对象
Student stu2(stu);//(1)会调用拷贝构造函数
Student stu3=stu ;//(2)会调用拷贝构造函数,这里和(1)是一样的,仅仅是写法不同而已
如果对象已经被创建,会调用赋值操作符而不是复制构造函数:
Student stu;
Student stu2;//在这里被创建
stu2 = stu;//这里调用赋值操作符重载(见后文)
完整示例代码1:
#include <iostream>//cin cout
using namespace std;
class Student
{
public:
//规则1:如果类的用户自己定义了构造函数
// ,编译器就不会自动合成类的默认构造函数Student(void)
//这样类就不存在默认构造函数了
//类的用户自己定义了拷贝构造函数(拷贝构造函数也算是一个构造函数)
//按照规则1,此时类不再拥有Student(void)这个函数
Student(const Student& from)
{
cout << "copy constructor called." << endl;
}
//由于上面已经定义了一个构造函数,按照规则1,
//Student stu;这条语句就会因为类不存在默认构造函数而编译报错
//为了能够让我们可以写Student stu;这条语句来创建对象
// ,我们在这里显示定义类的默认构造函数
Student(void)
{
cout << "default constructor called." << endl;
}
};
int main(int argv, char* argc[])
{
cout << "flag1" << endl;//打印标记信息,用来查看函数执行的顺序
Student stu;//先定义一个对象
cout << "flag2" << endl;//打印标记信息,用来查看函数执行的顺序
Student stu2(stu);//(1)会调用拷贝构造函数
cout << "flag3" << endl;//打印标记信息,用来查看函数执行的顺序
Student stu3 = stu;//(2)会调用拷贝构造函数,这里和(1)是一样的,仅仅是写法不同而已
cout << "flag4" << endl;//打印标记信息,用来查看函数执行的顺序
return 0;
}
2 给函数传递值类型参数的时候
void test_function(Student s)
{//s在该函数被调用的时候创建,该函数执行完之后释放
s.m_name = "李四";//修改s的名字
}
int main()
{
Student stu("张三");
test_function(stu);//(1)创建stu的副本,函数内使用副本
cout<<stu.m_name;//还是输出“张三”,因为修改的是,函数内的副本
}
完整示例代码2:
#include <iostream>//cin cout
#include <string>
using namespace std;
class Student
{
public:
Student(const Student& from)//拷贝构造函数
{
cout << "copy constructor called." << endl;
}
//如果只提供上面的拷贝构造函数,编译器就不再生成默认构造函数
//,会而导致类对象就不可以直接创建,所以还需要提供一个默认构造函数
Student(void)
{
cout << "default constructor called." << endl;
}
Student(const string& name) :m_name(name)
{
cout << "string constructor called." << endl;
}
string m_name;//存放学生姓名
};
void test_function(Student s)
{//s在该函数被调用的时候创建,该函数执行完之后释放
cout << "flag2" << endl;
s.m_name = "李四";//修改s的名字
cout << "flag3" << endl;
}//s释放的时刻
int main()
{
cout << "flag0" << endl;
Student stu("张三");
cout << "flag1" << endl;
test_function(stu);//(1)创建stu的副本,函数内使用副本
cout << "flag4" << endl;
cout << stu.m_name;//还是输出“张三”,因为修改的是,函数内的副本
}
3 函数返回值类型对象的时候
Student get_copy(void)
{
Student s;
return s;//这里以s为参数构造构造一个副本,并返回副本,这里发生了拷贝
}
完整示例代码3:
#include <iostream>//cin cout
#include <string>
using namespace std;
class Student
{
public:
Student(const Student& from)//拷贝构造函数
{
cout << "copy constructor called." << endl;
}
//如果只提供上面的拷贝构造函数,编译器就不再生成默认构造函数
//,会而导致类对象就不可以直接创建,所以还需要提供一个默认构造函数
Student(void)
{
cout << "default constructor called." << endl;
}
};
Student test_function(void)
{//s在该函数被调用的时候创建,该函数执行完之后释放
cout << "flag2" << endl;
Student stu;
cout << "flag3" << endl;
return stu;
}//s释放的时刻
int main()
{
cout << "flag1" << endl;
test_function();//(1)创建stu的副本,函数内使用副本
cout << "flag4" << endl;
}
拷贝对象发生了什么
1 先构造对象:分配内存空间
2 对应成员赋值:拷贝数据