目录
一:公共接口(提供类外接口)
属性是私有的,若是类外需要使用到,则编写 get,set方法
get方法 return返回,可以在类外部自己获取类的私有成员属性
set方法 赋值,可在类外部自己设置修改类的私有成员属性 对于整数使用=赋值,对于字符数组使用strcpy,但是对于字符数组也可以使用=赋值,需要将char数据类型改为string即可=赋值
下面是get/set方法 编写的简单示例
int getHeight(){return height;}
void setHeight(pheight){height = pheight};
二:拷贝构造
拷贝构造
示例如下
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
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;
}
main.c:
#include<iostream> //C++输入输出库
using namespace std; //std标准命名空间
#include"CFrog.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
//析构函数
//析构函数
三:拷贝构造函数 基本概念
1. 使用一个已经存在的对象来初始化一个新的本类的对象
Frog frog2(10,"gray","hama");
Frog frog3 = frog2; //类对象赋值 执行拷贝构造
2. 拷贝构造函数的声明:只有一个参数并且参数为该类对象的引用
类对象赋值,用已经存在的对象去生成一个新的对象,也就是拷贝构造函数
Frog(Frog &frog); //拷贝构造
如果类中没有说明复制构造函数,则系统自动生成一个缺省复制构造函数,作为该类的公有成员
类对象赋值,若是没有写拷贝构造函数,就会走系统默认的拷贝构造函数(注意只是浅拷贝)
因此,在类的设计中,如果有函数参数是 指针数据类型,需要自己编写拷贝构造函数,避免浅拷贝的一改全改的发生
浅复制:将对象数据成员的值进行简单的复制, 最好利用系统自动生成的复制构造函数,已完成浅复制
深复制:不仅将对象数据成员的值进行复制,而且对指针型数据成员生成新空间,然后复制对应的值
浅拷贝:若对象成员是指针,(复制地址把值也改变了)会一改全改,需要自己去写一个拷贝构造函数
深拷贝:对指针数据成员开空间,然后复制对应的值
四:触发拷贝构造的3种情况
1.类对象直接赋值
CLabel name = title;
2.类对象作为函数参数时(建立局部对象)
void copy(CLabel lab); //类对象作为函数参数
3.函数返回是类对象时(建立临时对象)
CLabel copy(CLabel lab); //函数返回是类对象
五:类对象作为函数参数
类对象作为函数参数时,值传递
执行系统默认的拷贝构造(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.按引用传参,共享一片内存空间;系统开销小,比较推荐
九:引用传参
1.类对象引用作为函数参数
void copy(CLabel &lab); //引用传参
void CLabel::copy(CLabel &lab) //引用传参
{
strcpy(content,lab.content); //共用一片内存空间
}
2.类对象引用作为函数返回
CLabel& copy(CLabel lab); //类对象引用作为函数返回
CLabel& CLabel::copy(CLabel lab) //类对象引用作为函数返回
{
strcpy(content,lab.content); //共用一片内存空间
return lab;
}
引用优势:
共享对象同一片内存空间不需要创建临时变量(不走拷贝构造 析构)
系统开销小 比较推荐
类 结构体 都是数据类型 可以类比int 当作是数据类型, 类是C++才有的 ,C没有
十:转换构造函数
转换构造(存在隐式转换的风险) 需要使用 explicit关键字来解决
转换构造函数 (一个参数)
转换构造函数,要传参一个参数,像下面直接赋值的写法是错误的,转换构造函数需要使用explicit关键字使得编辑器能够提醒此写法错误:
CLabel pwd =20; (转换构造函数,无参不可) 把20变成了CLabel类型(数据类型) (类)
是一个隐式转换 编译链接却没有问题,需要使用关键字explicit加以解决,如下:
声明写上 explicit CLabel(int x); //转换构造 按上面加粗的错误写法就会在编译的时候出现报错
正确的写法应该是CLabel pwd(20); 编译链接就没有问题了,因此转换构造在函数声明时候要写上explicit关键字
十一:C++的几种构造函数
默认构造:无参
普通(带参)构造:2参及以上
转换构造:1参 关键字explicit
拷贝构造又叫复制构造
十二:深拷贝 & 浅拷贝
深拷贝:自己写拷贝构造函数,为指针数据成员开空间再复制
浅拷贝:系统默认的拷贝构造函数是浅拷贝,复制地址,会一改全改
十三:析构函数作用
系统分配的空间会自动回收
程序员手动开空间,就需要手动释放,如
malloc需要free
new需要delete
那么,构造后就需要析构
析构函数没有参数,因此析构函数不能被重载