0
点赞
收藏
分享

微信扫一扫

C++拷贝构造函数的理解

小龟老师 2022-04-21 阅读 74
c++

一:属性是私有的,若是类外获取,使用get,set方法

使用get set方法

int getHeight(){return height;}

void setHeight(pheight){height = pheight};

二:拷贝构造

1.CFrog.h

#ifndef CFROG_H
#define CFROG_H

//成员变量 属性:height color name
//成员函数 行为:jump  eat  digist

class Frog
{
public:  
	Frog();  
	Frog(int pheight,char pcolor[],char pname[]);
    Frog(Frog &frog);  //拷贝构造
	~Frog();
    void jump();
	void eat();
	void digist();
	void setName(char *newName);
private:    
	int height;     //高度  
	char color[20]; //颜色  
	char *name;     //名字  
protected:
};

#endif

2.CFrog.cpp

#include"CFrog.h"
#include<iostream>
using namespace std;

Frog::Frog()   //构造函数没有函数类型
{
	cout<<"默认构造"<<endl;
	height = 5;
	strcpy(color,"green");
	name = (char *)malloc(20);
	memset(name,0,20);
	strcpy(name,"guagua");
}

Frog::Frog(int pheight,char pcolor[],char pname[])
{
	cout<<"带参构造"<<endl;
	height = pheight;
	strcpy(color,pcolor);
	name = (char *)malloc(20);
	memset(name,0,20);
	strcpy(name,pname);
}

void Frog::jump()
{
	cout<<name<<"jump"<<endl;
}

void Frog::eat()
{
	cout<<name<<"eat"<<endl;
	digist();
}

void Frog::digist()
{
	cout<<"digist"<<endl;
}

//用成员函数去访问成员内部私有变量
//设置名称 重命名
void Frog::setName(char *newName)
{
	name = (char *)malloc(20);
	memset(name,0,20);
	strcpy(name,newName);
}

//拷贝构造函数
Frog::Frog(Frog &frog)  //引用与原变量共享一片内存空间
{
	height = frog.height;
	
	name = (char *)malloc(20);
	memset(name,0,20);
	strcpy(name,frog.name);
	
	strcpy(color,frog.color);
	
	cout<<"拷贝构造"<<endl;
}

Frog::~Frog()
{
	//释放
	free(name);
	cout<<"析构函数"<<endl;
}

3.main.c

#include<iostream>  //C++输入输出库
using namespace std; //std标准命名空间
#include"CFrog.h"
#include"CBug.h"
#include<conio.h>
#include<ctime>

int main()
{	
	Frog frog2(10,"gray","hama");
	Frog frog3 = frog2;  //类对象赋值  执行拷贝构造
	frog2.jump();
	frog3.jump();

	frog3.setName("xiaogongzhu");
	frog2.jump();  //对象调用成员函数
	frog3.jump();  //对象调用成员函数
	return 0;
}
//带参构造
//拷贝构造
//hamajump
//hamajump
//hamajump
//xiaogongzhujump
//析构函数
//析构函数

三:拷贝构造函数知识点

使用一个已经存在的对象来初始化一个新的本类的对象

声明:只有一个参数并且参数为该类对象的引用

如果类中没有说明复制构造函数,则系统自动生成一个缺省复制构造函数,作为该类的公有成员。

类对象赋值,用已经存在的对象生成新的对象--拷贝构造函数

类对象赋值,若是没有写拷贝构造函数,就会走系统默认的拷贝构造函数(只是浅拷贝)

复制:将对象数据成员的值进行简单的复制(最好利用系统自动生成的复制构造函数,已完成浅复制

深复制:不仅将对象数据成员的值进行复制,而且对指针型数据成员生成新空间,然后复制对应的值

浅拷贝:若对象成员是指针,(复制地址把值也改变了)会一改全改,需要自己去写一个拷贝构造函数

深拷贝:对指针数据成员开空间,然后复制对应的值

四:触发拷贝构造的3种情况

1.类对象直接赋值 CLabel name = title;

2.类对象作为函数参数时(建立局部对象)

3.函数返回是类对象时(建立临时对象)

五:类对象作为函数参数时,值传递。执行系统默认的拷贝构造(1次)

void copy(CLabel lab);  //类对象作为函数参数
void CLabel::copy(CLabel lab)  //按值传递 对象赋值 执行系统copy构造
{
strcpy(content,lab.content);   //形参的生命周期 调用创建走拷贝构造 用完释放析构
}

空间利用频繁,开销比较大

六:函数返回是类对象时,类对象也是函数参数。执行系统默认的拷贝构造(2次)

CLabel copy(CLabel lab);  //函数返回是类对象
CLabel CLabel::copy(CLabel lab)//类对象作为函数参数 执行系统copy构造
{
   strcpy(content,lab.content);   
   return lab;//函数返回是类对象
}

七:什么时候需要自己写拷贝构造

答:类对象中有指针数据成员的时候才需要自己写拷贝构造。

八:函数传参

1.按值传递(值传参消耗的空间特别大)

2.按地址传递(形参是指针)

3.按引用传参,共享一片内存空间。系统开销小,比较推荐。

九:引用传参

类对象引用作为函数参数

void copy(CLabel &lab);  //引用传参
void CLabel::copy(CLabel &lab) //引用传参
{
  strcpy(content,lab.content);   //共用一片内存空间
}

类对象引用作为函数返回

CLabel& copy(CLabel lab);  //类对象引用作为函数返回
CLabel& CLabel::copy(CLabel lab) //类对象引用作为函数返回
{
  strcpy(content,lab.content); //共用一片内存空间
  return lab;
}

 小结:共享对象同一片内存空间不需要创建临时变量(不走拷贝构造 析构)系统开销小   比较推荐。

十:转换构造函数

转换构造(存在隐式转换的风险)  用explicit关键字解决

转换构造函数 (一个参数)

类 结构体 都是数据类型 很int 一样 数据类型。类是C++才有的。

错误:

CLabel pwd =20; (转换构造函数)  把20变成CLabel类型(数据类型)(类)

//隐式转换 编译链接却没有问题值得注意(用关键字explicit解决)

正确:

声明写上 explicit CLabel(int x);  //转换构造    编译链接就会报错

应该CLabel pwd(20); 编译链接就没有问题了。

十一:构造函数

1.默认构造:无参

2.普通构造:2参及以上

3.转换构造:1参 关键字explicit

4.拷贝构造又叫复制构造

十二:深拷贝和浅拷贝

深拷贝:自己写拷贝构造函数,为指针数据成员开空间再复制

浅拷贝:系统默认的拷贝构造函数是浅拷贝,复制地址,会一改全改

十三:析构

系统分配的空间会自动回收。

程序员手动开空间,就需要手动释放。

malloc需要free

new需要delete

构造就需要析构

析构函数没有参数,因此析构函数不能被重载。

举报

相关推荐

0 条评论