一. 什么是拷贝构造函数:
- 默认拷贝构造函数(浅拷贝):
浅拷贝构造函数即系统自带的拷贝构造函数,当程序将一个已经定义的对象数据给另一个对象作为初始值时,并且程序为自定义拷贝构造函 数,系统就会自动调用默认拷贝构造函数.
调用形式 :
class Human {
public:
Human();
string getName();
private:
string name = "张三";
};
Human::Human() {
name = "无名";
}
int main() {
Human h1; //调用自定义的构造函数
Human h2 = h1; //调用拷贝构造函数
Human h3(h1); //调用拷贝构造函数
return 0;
}
- 自定义拷贝构造函数(深拷贝):
深拷贝构造函数即程序员自己定义的拷贝构造函数.
调用形式:
class Human {
public:
Human();
Human(Human&);
string getName();
private:
string name = "张三";
};
Human::Human() {
name = "无名";
}
Human::Human(Human&other) {
cout << "调用拷贝构造函数" << endl;
name = other.name;
}
int main() {
Human h1; //调用自定义的构造函数
Human h2 = h1; //调用拷贝构造函数
Human h3(h1); //调用拷贝构造函数
return 0;
}
二.为什么要自己定义拷贝构造函数
- 默认拷贝构造函数(浅拷贝):
指针拷贝时,拷贝对象h2的里面指针数据指向被拷贝函数(h1),因此当h1的addr改变时,h2的addr也随之改变.
- 自定义拷贝构造函数(深拷贝):
为拷贝对象h2创建独立的内存,指针指向这块内存,即使h1改变,h2也不会随之变.
- 区别:
默认拷贝函数中的h2的指针变量addr会会随着h1的改变而改变,自定义拷贝函数为h2的addr分配了一块堆地址,因此h2不会随着h1的改变而改变.所以默认拷贝函数存在很大的安全隐患.
#include<iostream>
#include<string>
#include<Windows.h>
using namespace std;
#define ADDR_LEN 64
class Human {
public:
Human();
Human(int, int);
Human(Human&);
void description();
string getName();
int getAge();
int getSalary();
void setAddr(char *);//修改地址
private:
string name = "张三";
int age = 18; //类内初始值,c++11才支持
int salary = 1800;
char *addr="China"; //地址
};
Human::Human() {
age = 18;
salary = 1800;
name = "无名";
addr = new char[ADDR_LEN];
strcpy_s(addr,ADDR_LEN,"China");
}
Human::Human(int age, int salary) {
this->age = age;
this->salary = salary;
addr = new char[ADDR_LEN];
strcpy_s(addr, ADDR_LEN, "China");
}
Human::Human(Human&other) {//相当于const Human &other=h1;
cout << "调用拷贝构造函数" << endl;
name = other.name;
age = other.age;
salary = other.salary;
}
void Human::description() {
cout << "age:" << age << "name:" << name << "salary:" << salary << "addr:" << addr << endl;
}
string Human::getName() {
return name;
}
int Human::getAge() {
return age;
}
int Human::getSalary() {
return salary;
}
void Human::setAddr(char *addr) {
if (!addr) {
return;
}
strcpy_s(this->addr,ADDR_LEN,addr);
}
int main() {
Human h1(25, 28000);//调用自定义的构造函数
Human h2 = h1; //调用拷贝构造函数
Human h3(h1); //调用拷贝构造函数
h1.description();
h2.description();
h3.description();
h1.setAddr("美国");
//修改地址之后<<endl;
h1.description();
h2.description();
h3.description();
system("pause");
return 0;
}
三.拷贝构造函数调用时机
- 创建一个对象的时候同时用另外一个对象创建初始值:Human h2=h1; Human h2(h1);
- 调用函数时,实参是对象,形参不是引用类型
如果函数的形参是引用类型,就不会调用拷贝构造函数(要在函数后加const,防止函数被
其他程序员修改,使程序更加安全,)
如:
void showMsg(Human man) {
man.description();
}
改为:
void showMsg(const Human &man) {
man.description();
}
- 函数的返回类型是类,而且不是引用类型
如果函数返回值是引用类型,就不会调用拷贝构造函数
如:
Human getBetterMan(const Human &man1, const Human &man2) {
if (man1.getSalary()>man2.getSalary()) {
return man1;
}
else{
return man2;
}
}
改为:
const Human &getBetterMan(const Human &man1, const Human &man2) {
if (man1.getSalary()>man2.getSalary()) {
return man1;
}
else{
return man2;
}
}
- 对象数组的初始化类表中,使用对象
如:
Human f1, f2, f3, f4;
Human F4[4] = {f1,f2,f3,f4};
源代码:
#include<iostream>
#include<string>
#include<Windows.h>
using namespace std;
#define ADDR_LEN 64
class Human {
public:
Human();
Human(int, int);
Human(const Human&);
void description()const;
string getName() const;
int getAge() const;
int getSalary() const;
void setAddr(char *);//修改地址
private:
string name = "张三";
int age = 18; //类内初始值,c++11才支持
int salary = 1800;
char *addr = "China"; //地址
};
Human::Human() {
age = 18;
salary = 1800;
name = "无名";
addr = new char[ADDR_LEN];
strcpy_s(addr, ADDR_LEN, "China");
}
Human::Human(int age, int salary) {
cout << "调用自定义构造函数" << endl;
this->age = age;
this->salary = salary;
addr = new char[ADDR_LEN];
strcpy_s(addr, ADDR_LEN, "China");
}
Human::Human(const Human&other) {//相当于const Human &other=h1;
cout << "调用拷贝构造函数" << endl;
name = other.name;
age = other.age;
salary = other.salary;
//为addr分配一块独立的内存,进行深拷贝
addr = new char[ADDR_LEN];
strcpy_s(addr, ADDR_LEN, other.addr);
}
void Human::description() const {
cout << "age:" << age << "name:" << name << "salary:" << salary << "addr:" << addr << endl;
}
string Human::getName()const {
return name;
}
int Human::getAge() const {
return age;
}
int Human::getSalary() const {
return salary;
}
void Human::setAddr(char *addr) {
if (!addr) {
return;
}
strcpy_s(this->addr, ADDR_LEN, addr);
}
/*
void showMsg(Human man) {
man.description();
}
1:调用函数 showMsg(h1);
在进行参数传递时,自动执行:Human man=h1;
在Human前加const,防止其他程序员通过该函数修改类的数据(增加程序的安全性)
但是在Human前加上const后,该引用就无法调用该类的方法,所以在定义方法后面加上const
*/
void showMsg(const Human &man) {
man.description();
}
/*
Human getBetterMan(const Human &man1, const Human &man2) {
if (man1.getSalary()>man2.getSalary()) {
return man1;
}
else{
return man2;
}
}
2:函数的返回类型是类,而且不是引用类型
为了避免使用拷贝构造函数将getBetterMan设为引用类型,但是要与(const Human &man1)类型保持一致,
要在开头添加const,
*/
const Human &getBetterMan(const Human &man1, const Human &man2) {
if (man1.getSalary()>man2.getSalary()) {
return man1;
}
else {
return man2;
}
}
int main() {
Human f1, f2, f3, f4;
/* Human F4[4] = {f1,f2,f3,f4};
3.相当于F[1]=f1,F[2]=f2,F[3]=f3,F[4]=f4;
*/
Human F4[4] = {f1,f2,f3,f4};
system("pause");
return 0;
}