拷贝构造函数

一. 什么是拷贝构造函数:

  1. 默认拷贝构造函数(浅拷贝):
    浅拷贝构造函数即系统自带的拷贝构造函数,当程序将一个已经定义的对象数据给另一个对象作为初始值时,并且程序为自定义拷贝构造函 数,系统就会自动调用默认拷贝构造函数.
    调用形式 :
class Human {
public:
	Human();
	string getName();
private:
	string name = "张三";
};
Human::Human() {
	name = "无名";
}
int main() {
	Human h1;				//调用自定义的构造函数
	Human h2 = h1;		//调用拷贝构造函数
	Human h3(h1);		//调用拷贝构造函数
	return 0;
}
  1. 自定义拷贝构造函数(深拷贝):
    深拷贝构造函数即程序员自己定义的拷贝构造函数.
    调用形式:
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;
}

二.为什么要自己定义拷贝构造函数

  1. 默认拷贝构造函数(浅拷贝):
    指针拷贝时,拷贝对象h2的里面指针数据指向被拷贝函数(h1),因此当h1的addr改变时,h2的addr也随之改变.
    图1.默认拷贝构造函数
  2. 自定义拷贝构造函数(深拷贝):
    为拷贝对象h2创建独立的内存,指针指向这块内存,即使h1改变,h2也不会随之变.
    图2.自定义拷贝构造函数
  3. 区别:
    默认拷贝函数中的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;
}

三.拷贝构造函数调用时机

  1. 创建一个对象的时候同时用另外一个对象创建初始值:Human h2=h1; Human h2(h1);
  2. 调用函数时,实参是对象,形参不是引用类型
    如果函数的形参是引用类型,就不会调用拷贝构造函数(要在函数后加const,防止函数被
    其他程序员修改,使程序更加安全,)

    如:
void showMsg(Human man) {
	man.description();
}

改为:

void showMsg(const Human &man) {
	man.description();
}
  1. 函数的返回类型是类,而且不是引用类型
    如果函数返回值是引用类型,就不会调用拷贝构造函数
    如:
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;
	}
}
  1. 对象数组的初始化类表中,使用对象
    如:
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;
}
  • 8
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值