C++类与对象——成员函数

类中的六种默认成员函数

  当我们定义了一个类,并且尚未给类中添加任何成员,此时为一个空类,但是看起来是空的,实际上编译器已经为我们隐式定义了六种默认的成员函数:构造函数、拷贝构造函数、析构函数、赋值运算符重载函数、取地址和const取地址操作符重载函数。
  那么这六种成员函数都各自具备什么样的属性呢?下面我们来看一下:

(一)构造函数

1、构造函数的写法:
  构造函数有三种方式,这里以日期类为例:

class Data
{
public:
	//1.无参构造
	Data(){}
	//2.全缺省构造
	Data(int year = 0, int month = 0, int day = 0)
		:_year(year)
		, _month(month)
		, _day(day)
	{
		……
	}
	//3.带参(非全缺省)构造
	Data(int year, int month, int day)
		:_year(year)
		, _month(month)
		, _day(day)
	{
		……
	}
private:
	int _year;
	int _month;
	int _day;
}

  上面的三种是构造函数的显示写法,而当我们并没有显示的写出以上任何一种构造函数时,编译器在我们创建对象时会自动生成并调用一个无参的默认构造函数,我们需要注意的是,在一个类中,只能同时存在一个默认构造函数,那么默认构造函数有哪些呢?

1.不显示写任何构造函数时,系统自带的构造函数;
2. 显示写出的无参的构造函数;
3.显示写出的全缺省的构造函数;

2、构造函数中的初始化
  在构造函数中,类的成员变量初始化的位置并不是在大括号之间的,而是在大括号之前就初始化好了的,我们将类的成员变量的初始化叫做参数列表

Data(int year = 0, int month = 0, int day = 0)
		:_year(year)
		, _month(month)
		, _day(day)
	{
		……
	}

  从“:”到第一个大括号之间的就是参数列表,也就是成员变量的初始化的写法格式,当然了,例子中的三个成员变量并不一定需要初始化,而在C++中有几类成员变量时必须要进行初始化的:

1.引用类型的成员变量;
2.const修饰的成员变量;
3.自定义成员变量(如果有默认构造,则不必初始化;如果没有默认构造,则必须进行初始化);

  在大括号里面则是成员变量的赋值,另外如果需要额外的资源开销,也可以在这里申请。
  另外还要注意成员变量的初始化顺序:不是按照参数列表中的顺序初始化,而是按照声明时候的顺序进行的初始化。所以我们在参数列表中的书写顺序尽量和声明时候的顺序一致。

3、构造函数调用格式:

Data d(2020,10,18);

4、构造的先后顺序

1、全局对象优先于局部对象
2、静态对象优先于普通对象

(二)拷贝构造函数

1、拷贝构造函数的写法:

Data(const Data& d){}

  拷贝构造是用已经存在的类类型对象来创建新的类类型对象,相当于是对已存在的类类型对象的一个拷贝;
  需要注意的是:

  • 因为拷贝构造相当于一个拷贝,所以所传的参数必须是对象的引用,如果这里我们不传引用的话,那么将会造成一个拷贝构造函数的无穷递归调用;
  • 传参时如果加const更好,可以直接调用拷贝构造,否则会先调用构造函数创建一个临时变量再进行拷贝;

2、显式拷贝构造和隐式拷贝构造的区别
  在我们不显式写出拷贝构造时,编译器也会自动生成一个拷贝构造,那么和我们写的区别在哪里呢?
  编译器默认的拷贝构造是字节拷贝浅拷贝),即只拷贝对象模型中的内容,不拷贝资源;
  如果有资源,必须显示定义拷贝构造,实现深拷贝把资源一并拷贝;

(三)析构函数

1、析构函数的写法:

~Data(){}

  析构函数无参无返回值,最前面有一个“~”;
  清理对象所调用的资源,不是销毁对象,对象生命周期结束时编译器自动调用,若无资源需要清理则可使用编译器默认生成的析构函数
2、显式析构函数和隐式析构的区别
  当我们的类中没有申请资源时,可以不写析构函数而使用编译器默认生成的;
  当我们的类中有资源的申请时,我们就必须要显式的写出析构函数并在其中释放掉申请的资源;
3、析构函数调用的先后顺序

与构造函数构造顺序完全相反

(四)赋值运算符重载函数

1、运算符重载函数的写法:

Data& operator=(const Data& d){}

  运算符重载函数的格式:

返回值类型  operator运算符(参数){}

  运算符重载的作用是为了使代码看起来更有可读性,并不是所有的运算符重载函数都会由编译器自动形成,只有赋值运算符重载函数才会由编译器自动生成;
2、运算符重载函数的参数个数
  普通的运算符重载函数,则参数个数和运算符需要个数一致;
  若为成员函数,则显示上参数少一个,this指针指向本对象,实际上是:

Data& operator=(const Data* this, const Data& d){}

  实际中是缺省了前面的this指针;
3、赋值运算符重载函数显式和隐式的区别
  编译器默认生成的也是字节拷贝浅拷贝),如有资源时也需要显式写出;
4、关于返回对象还是返回对象的引用
  当运算结束后改变本对象的值时,则返回对象的引用;
  当运算结束后未改变本对象的值时,则返回对象或者对象的引用都可以;
5、不能被重载的运算符

.*
:: 
sizeof 
?: 
.

(五)const成员

1、const修饰

1.int* const ptr:不能修改指针的指向,但是可以修改指针指向的内容
2.const int* ptr:不能修改指针指向的内容,但是可以修改指针的指向
3.const int* const ptr:指针的指向和指针指向的内容都不可修改

2、const修饰的成员函数
  写法:

void print()const{}

  这种写法实际上表示为:

void print(const Data* this){}

  const修饰的成员函数表示为不能改变该对象的内容,相当于函数从可读可写变为了只读;
  当用const修饰时

const对象可以调用const和非const成员函数
非const对象只能调用非const成员函数

  总结为一句话就是权限不可被放大

(六)取地址和const取地址操作符重载函数

1、取地址操作符重载函数写法

Data* operator&()
{
	return this;
}

2、const取地址操作符重载函数

const Data* operator&()const
{
	return this;
}

这两个函数一般不需要重载,直接使用编译器自动生成的即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值