类与对象2- - -六个默认成员函数

本文详细介绍了C++中类的六个默认成员函数,包括构造函数、析构函数、拷贝构造函数、赋值操作符重载、取地址操作符重载及const成员函数。文中通过具体的代码示例解释了这些函数的作用、特性和使用场景。

类的六个默认成员函数
1.构造函数- - -初始化
2.析构函数- - -清理
3.拷贝构造函数- - -用同类对象初始化创建对象
4.赋值操作符重载- - -把一个对象赋值给另外一个对象
5.取地址操作符重载
6.const成员函数

注意:一个空类在主流编译器中占一个字节,但是仍然具有六个成员函数
构造函数

#include <stdio.h>
#include <iostream>
using namespace std;

//构造函数
class Date
{
public:
	//带参构造函数
	Date(int year,int month,int day){
		_year = year;
		_month = month;
		_day = day;
	}
#if 0
	//无参构造函数
	Date(){

	}
	//全缺省构造函数
	Date(int year=2019, int month=7, int day=16){
		_year = year;
		_month = month;
		_day = day;
	}
#endif
	void SetDate(int year,int month,int day){
		_year = year;
		_month = month;
		_day = day;
	}

	void PrintDate(){
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

void TestDate(){
	Date d1(2019, 7, 16);//调用有参构造函数
	Date d2();//调用无参构造函数
	d1.PrintDate();

}
/*如果类中没有显式定义构造函数,则编译器会自动生成一个无参的默认构造函数,
若用户定义,则不再生成
无参构造函数和全缺省的构造函数都称为默认构造函数,但是只能存在一个
一般用全缺省
注意:无参构造函数,全缺省构造函数,编译器自动生成的构造函数都可以认为是默认成员函数

*/
int main(){
	TestDate();
}


构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,保证每个数据成员都有一个合适的初始值,并且在对象生命周期内只调用一次
构造函数没有返回值类型,不用加void
一个类中,构造函数可以有多个,对象参数不同,构造函数不同
构造函数主要任务不是在空间中创建对象,而是初始化对象
构造函数的特征:
1.函数名与类名相同
2.无返回值
3.对象实例化时编译器自动调用对应的构造函数
4.构造函数可以重载
补充

#if 0
class Date
{
public:
	// 全缺省的构造函数
	Date(int year = 1900, int month = 1, int day = 1) //冒号之后是初始化参数列表
		: _year(year)
		, _month(month)
		, _day(day)
	{
		// 一旦进入到构造函数体中,对象已经创建成功
		// 进行的是赋值,不是初始化,函数体就不再写以下内容了,而是写其他内容
 		//_year = year;
 		//_month = month;
 		//_day = day;
 		
	}
	//拷贝构造函数同样
	Date(const Date& d)
		: _year(d._year)
		, _month(d._month)
		, _day(d._day)
	{}


private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(2019, 6, 16);
	Date d2(d1);
	return 0;
}
#endif

析构函数

//析构函数

#include <assert.h>
#include <malloc.h>
typedef int DataType;

class SeqList{
public:
	SeqList(size_t capacity=3){
		_array = (DataType*)malloc(sizeof(DataType)*capacity);
		if (nullptr==_array)
		{
			assert(0);
			return;
		}
		_capacity = capacity;
		_size = 0;
	}
		//析构函数
	~SeqList(){
			if (_array)
			{
				free(_array);
				_array = nullptr;
			}
		}
private:
	DataType* _array;
	size_t _size;
	size_t _capacity;
};

void TestSeqlist(){
	SeqList s;
}

int main(){
	TestSeqlist();
	return 0;
}

析构函数不是完成对象的销毁,销毁是由编译器完成的,而是在对象销毁时
自动调用析构函数,完成类的一些资源清理工作
(堆上的空间需要用析构函数释放)
析构函数的特性:
1.析构函数是在类名前加上取反符号~
2.无参数无返回值不能重载
3.一个类有且只有一个析构函数,未显式定义则编译器自动生成默认的的析构函数
4.对象生命周期结束时,C++编译系统自动调用析构函数
5.编译器生成的默认析构函数,会对自定类型成员调用它的析构函数

拷贝构造函数

//拷贝构造函数
class Date{
public:
	//全缺省的构造函数
	Date(int year=2019,int month=7,int day=16){
		_year = year;
		_month = month;
		_day = day;
	}
	//拷贝构造函数
	Date(const Date& d){
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	void SetDate(int year, int month, int day){
		_year = year;
		_month = month;
		_day = day;
	}
	void PrintData(){
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

void TestDate(){
	Date d1;
	//Date d2(2019,7,16);
	Date d3(d1);//使用d2拷贝构造d3
}
int main(){
	TestDate();
	return 0;
}

拷贝构造函数:
只有单个形参,该形参是对本类类型对象的引用(常用const修饰)
用const修饰的目的是复制期间不改变原参数内容
在用已存在的类类型对象创建新对象时由编译器自动调用
拷贝构造函数的特征:
1.拷贝构造函数是构造函数的重载形式(同一作用域,名字相同,参数列表不同)
2.拷贝构造函数的参数只有一个且必须使用引用传参(例如Date&d或者Date d3(d2)用d2构造d3),
使用传值方式会引发无穷递归调用
3.若未显式定义,则系统生成默认的拷贝构造函数,默认的拷贝构造函数
按对象内存存储按字节序完成拷贝,这种拷贝我们称之为浅拷贝或者值拷贝
如果不给出拷贝构造函数的话,默认的拷贝构造函数使两对象的地址相同,两次释放空间会崩溃- - -浅拷贝

注意:
日期类存放的是整形变量,可以不写拷贝构造函数
而string等位于堆上,位于堆上的涉及资源释放,必须给出拷贝构造函数
赋值也一样,默认的赋值运算也是浅拷贝,同时会导致资源泄露

运算符的重载

//运算符的重载
class Date{
public:
	//全缺省的构造函数,即给一个初始值
	Date(int year = 2019, int month = 7, int day = 16){
		_year = year;
		_month = month;
		_day = day;
	}
	//拷贝构造函数
	Date(const Date& d){
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	void SetDate(int year, int month, int day){
		_year = year;
		_month = month;
		_day = day;
	}
	void PrintData(){
		cout << _year << "-" << _month << "-" << _day << endl;
	}
	
	//运算符重载
	Date operator+(int days){//注意这里如果用Date&,,表示返回值不能是栈上的空间,而tmp就是栈上的空间,出了作用域,tmp就会被销毁
		Date tmp(*this);//创建一个临时对象来保证+之后原本的day不变
		tmp._day += days;
		return tmp;
	}
	//如果把其当做全局函数时,需要两个参数d1和d2,但是在类中定义时,this指针也算一个参数
	bool operator ==(const Date &d){
		return _year == d._year &&
			_month == d._month &&
			_day == d._day;
	}
	bool operator !=(const Date &d){
		return _year == d._year &&
			_month == d._month &&
			_day == d._day;
	}
#if 0
	//或者
	bool operator ==(const Date &d){
		return !(*this == d);
	}
#endif
	// 前置++
	Date& operator++()
	{
		_day += 1;
		return *this;//返回+1之后的新的值
	}

	// 后置++
	Date operator++(int)
	{
		Date temp(*this);
		_day += 1;
		return temp;//返回+1之前的旧值
	}


	Date& operator--()
	{
		_day -= 1;
		return *this;
	}

	Date operator--(int)
	{
		Date temp(*this);
		_day -= 1;
		return temp;
	}

	//赋值运算符重载
	/*
	赋值运算符需要注意的几点
	1.参数类型
	2.返回值
	3.检测自己给自己赋值
	4.返回*this
	5.如果没有显示定义赋值运算符重载,则编译器也会生成一个,但是是浅拷贝
	*/
	Date& operator=(const Date& d){
		if (this != &d)//排除自己给自己赋值的情况
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this;//注意返回值为引用
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	int a = 10;
	int b = 10;
	int c = 100;

	a = b = c;//不能连续赋值
	Date d1(2019, 6, 16);
	Date d2(2019, 6, 17);
	Date d3(2019, 6, 18);
	Date& d4 = d1;
	d4 = d1;//相当于自己给自己赋值
	//d1 = d2;   //等价于 d1.operator=(d2); //  底层Date::operator=(&d1, d2);

	//d1 = d2 = d3;  //实际上的赋值顺序:d1 = (d2 = d3)
	d1.operator=(d2.operator=(d3));

	return 0;
}

C++为了加强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数
也具有其返回值,函数名及其参数列表,其返回值与参数列表与普通函数类似
**函数名字为:*关键字operator后面接需要重载的运算符的符号
函数原型:返回值类型operator操作符(参数列表)
注意:
不能通过连接其他运算符号来创建新的操作符,如operator@
重载操作符必须有一个类类型或者枚举类型的操作数,即必须要有一个自定义类型的参数
用于内置类型的操作符,其含义不能改变,例如:内置的整形+,不能改变其含义
作为类成员的重载函数时,其形参看起来比操作数数目少1,成员函数的操作符
有一个默认的形参this,限定为第一个形参
.
;; sizeof ?: .
以上五个运算符不能形成重载

const成员函数

class Date
{
public:
	Date(int year, int month, int day){
		_year = year;
		_month = month;
		_day = day;
	}

	// const成员函数中不能修改成员变量
	// const修饰this指针,表明:当前对象中的内容不允许被修改

	

	// this指针的类型Date* const  表明this指针不能修改,但是成员变量可以修改
	void PrintDate()
	{
		_day = 1;
		cout << _year << "-" << _month << "-" << _day << endl;
	}

	// this指针的类型const Date* const  表明this指针指向的地址和地址保存的内容都不能修改
	void PrintDate()const
	{
		//this->_day = 1;
		cout << _year << "-" << _month << "-" << _day << endl;
	}
	//以上两个函数可以形成重载


	bool operator==(const Date& d)const
	{
		//_day = 1;
		//d._day = 1;
		return _year == d._year &&
			_month == d._month &&
			_day == d._day;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main(){
	Date d(2019, 7, 17);
	d.PrintDate();
	cout << &d << endl;
	return 0;
}

注意:
1.const对象不可以调用非const成员函数,但是非const对象可以调用const成员函数,相当于只读
2.const成员函数内不可以调用其他非const成员函数,但是非const成员函数内可以调用其他的const成员函数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值