(C++初阶)类&对象 二

目录

1. 类的6个默认成员函数

2. 构造函数

3. 析构函数

4. 拷贝构造函数

5. 赋值操作符重载

6. 日期类的实现

7. const成员函数

8. 取地址及const取地址操作符重载


1. 类的6个默认成员函数

1.1  构造函数:初始化。
1.2  析构函数:清理
1.3  拷贝构造函数:使用同类对象初始化创建对象。
1.4  赋值运算符的重载:把一个对象赋值给另外一个对象。
1.4  取地址重载:普通对象和const对象取地址。
1.5  针对我们丕写编译默认生成的总结:
      ① 构造和析构的特性是类似,我们不写,编译器内置类型不处理,自定义类型调用它的构造和析构处理。
      ② 拷贝构造和赋值重载特性是类似的,内置类型会完成浅拷贝,自定义类型会调用他们的拷贝构造和赋值重载。

2. 构造函数

2.1构造函数: 是一个特殊的成员函数,名字与类名相同 , 创建类类型对象时由编译器自动调用 ,保证每个数据成员 都有 一个合适的初始值,并且 在对象的生命周期内只调用一次
2.2构造函数是特殊的成员函数 ,需要注意的是,构造函数的虽然名称叫构造,但是需要注意的是构造函数的主 要任务 并不是开空间创建对象,而是初始化对象
2.3特征:
     函数名与类名相同。
     无返回值。
     对象实例化时编译器自动调用对应的构造函数。
     构造函数可以重载。
2.4 默认构造函数:不用参数就可以调用的构造函数。
①我们不写,编译器自动生成的。
②我们自己写的无参的。
③我们自己写的全缺省。

2.5 例

//类里面我们什么函数都不写的时候,编译器会自动生成六个成员函数,这六个函数就叫默认成员函数。
//1、构造函数->对象的初始化。
//
class Date
{
public:
	//构造函数,函数名与类名相同,需要我们自己写。
	//在对象实例化的时候自动调用,保证对象一定会初始化。
	//全缺省
	Date(int year=2022, int month=6, int day=26)
	{
		_year = year;  
		_month = month;
		_day = day;    
	}
	void print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(2022, 6, 25);
	d1.print();

	Date d2;
	d2.print();
	return 0;
}

3. 析构函数

3.1 概念:
析构函数:与构造函数功能相反,析构函数不是完成对象的销毁,局部对象销毁工作是由编译器完成的。而 对象在销毁时会自动调用析构函数,完成类的一些资源清理工作。
3.2 特性:
析构函数 是特殊的成员函数。
1. 析构函数名是在类名前加上字符 ~
2. 无参数无返回值。
3. 一个类有且只有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。
4. 对象生命周期结束时, C++ 编译系统系统自动调用析构函数。

3.3 示例

class Date
{
public:
	Date(int capacity = 4)
	{
		_a = (int*)malloc(sizeof(int) * capacity);
		_capacity = capacity;
		_size = 0;
	}
	void push(int x)
	{
		;
	}
	//析构函数
	~Date()
	{
		//资源的清理。
		free(_a);
		_a = nullptr;
		_size = _capacity = 0;
	}

private:
	int* _a;
	int _size;
	int _capacity;
};

int main()
{
	//因为对象是定义在函数中的,而函数调用会建立栈帧,栈帧中的对象构造和析构也要遵循先进后出原则。
	//d1 先构造 d2后构造,d2 先析构 d1 后析构。
	Date d1;
	d1.push(1);
	d1.push(2);
	d1.push(3);

	Date d2;
	d2.push(1);
	d2.push(2);
	d2.push(3);

	return 0;
}

4. 拷贝构造函数

4.1  概念:

 拷贝构造函数只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),   在用已存在的类类型对象创建新对象时由编译器自动调用。

4.2  拷贝构造函数也是特殊的成员函数,其特征如下:

拷贝构造函数 是构造函数的一个重载形式
拷贝构造函数的 参数只有一个 必须使用引用传参 ,使用 传值方式会引发无穷递归调用。
若未显示定义,系统生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷 贝,这种拷贝我们叫做浅拷贝,或者值拷贝。
4.3 示例
//拷贝构造函数--拷贝初始化
class Date
{
public:
	//构造函数
	Date(int year = 2022, int month = 6, int day = 26)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	//析构函数
	~Date()
	{
		//资源的清理。
	}
	//拷贝构造函数
	//必须传引用传参,不然会发生无穷递归。
	//是默认成员函数,我们不写编译器会自动生成拷贝构造函数。
	//这个拷贝构造对内置类型会完成浅拷贝,或者值拷贝。
	//像Stack这样的类不能是浅拷贝。需要深拷贝。如果浅拷贝,会发现生析构两次的问题。
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

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

int main()
{
	Date d1(2022, 6, 25);
	Date d2(d1);

	return 0;
}

5. 赋值操作符重载

5.1 运算符重载

①  ‘ .* ’、‘  ::  ’、‘ sizeof ’、‘ ?: ’、‘ . ’ 这五个运算符不能重载。

② C++ 为了增强代码的可读性引入了运算符重载 运算符重载是具有特殊函数名的函数 ,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。函数名字为:关键字operator 后面接需要重载的运算符符号 。函数原型:返回值类型  operator 操作符 ( 参数列表 )

5.2 示例

class Date
{
public:
	//构造函数
	Date(int year=2022, int month=6, int day=26)
	{
		_year = year;  
		_month = month;
		_day = day;    
	}
	//析构函数
	~Date()
	{
		//资源的清理。
		//cout << "~Date" << endl;
	}
	//运算符重载
	//当运算符有两个操作数时,第一个操作数是左操作数,第二个操作数是右操作数。
	bool operator==(Date x)
	{
		return _year == x._year\
			&& _month == x._month\
			&& _day == x._day;
	}
	bool operator<(Date x)
	{
		if (_year < x._year)
		{
			return true;
		}
		else if (_year == x._year)
		{
			if (_month < x._month)
			{
				return true;
			}
			else if (_month == x._month)
			{
				if (_day < x._day)
					return true;
			}
		}
		return false;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(2022, 6, 25);
	Date d2(2022, 6, 26);
	//内置类型语言层面就支持运算符。
	//自定义类型默认不支持。C++可以用运算符重载,来让类对象支持某个运算符。
	cout<<(d1 == d2)<<endl;
	cout << (d1 < d2) << endl;
	return 0;
}
5.3 赋值运算符重载
示例:
//赋值运算符重载
class Date
{
public:
	//构造函数
	Date(int year=2020, int month=1, int day=11)
	{
		_year = year;  
		_month = month;
		_day = day;    
	}
	//析构函数
	~Date()
	{
		//资源的清理。
		//cout << "~Date" << endl;
	}
	//运算符重载
	//当运算符有两个操作数时,第一个操作数是左操作数,第二个操作数是右操作数。
	//写成成员函数省略掉一个操作数。因为隐含一个this
	//bool operator==(Date* this,const Date& x) 
	bool operator==(const Date& x)  
	{
		return _year == x._year\
			&& _month == x._month\
			&& _day == x._day;
	}
	bool operator<(const Date& x)
	{
		if (_year < x._year)
		{
			return true;
		}
		else if (_year == x._year)
		{
			if (_month < x._month)
			{
				return true;
			}
			else if (_month == x._month)
			{
				if (_day < x._day)
					return true;
			}
		}
		return false;
	}
	//赋值运算符重载
	Date& operator=(const Date& x)
	{
		if (this != &x)//不是自己给自己赋值,才需要拷贝。
		{
			_year = x._year;
			_month = x._month;
			_day = x._day;
			return *this;
		}
	}
	void print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(2022, 6, 25);
	Date d2(2022, 6, 26);
	Date d3;
	d1.print();
	d2.print();
	d3.print();
	//内置类型语言层面就支持运算符。
	//自定义类型默认不支持。C++可以用运算符重载,来让类对象支持某个运算符。
	d3= d2 = d1;
	d2.print();
	d3.print();
	return 0;
}

6. 日期类的实现

6.1 Date.cpp
#include"date.h"

inline int GetMonthDay(int year, int month)
{
	//存储平年每月天数
	static int DayArray[13] = { 0,31,28,31,30,31,30,31,31,30,31,30 };
	int day = DayArray[month];
	if (month == 2 && (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
	{
		day=29;
	}
	return day;
}
//构造函数
Date::Date(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;
	//检查日期的合法性
	if (year>=0 && month>0 && month<13 && day<= GetMonthDay(year,month) && day>0)
	{
		cout << "合法日期" << endl;
		cout << year << "年" << month << "月" << day << "日" << endl;
	}
	else
	{
		cout << "非法日期" << endl;
		cout << year << "年" << month << "月" << day << "日" << endl;
	}

}
void Date::print()
{
	cout << _year << "年" << _month << "月" << _day << "日" << endl;
}
//析构、拷贝构造、赋值重载,可以不写,默认生成的就够用了
//像Stack这样的才需要自己写。
Date& Date:: operator+=(int day)
{
	if (day < 0)
	{
		*this -= -day;
	}
	else
	{
		_day += day;
		while (_day > GetMonthDay(_year, _month))
		{
			_day -= GetMonthDay(_year, _month);
			_month++;
			if (_month > 12)
			{
				_month = 1;
				_year++;
			}
		}
	}
	return *this;
}
Date Date:: operator+(int day)
{
	Date ret(*this);
    //复用+=
	ret += day;
	return ret;
}
Date& Date::operator-=(int day)
{
	if (day < 0)
	{
		*this += -day;
	}
	else
	{
		_day -= day;
		while (_day <= 0)
		{
			--_month;
			if (_month <= 0)
			{
				_month = 12;
				--_year;
			}
			_day += GetMonthDay(_year, _month);
		}
	}
	return  *this;
}
Date Date:: operator-(int day)
{
	Date ret(*this);
	//复用-=
	ret -= day;
	return ret;
}
Date& Date::operator++()
{
	*this += 1;
	return *this;
}
Date Date::operator++(int)
{
	Date tem(*this);
	*this += 1;
	return tem;
}
Date& Date::operator--()
{
	*this -= 1;
	return *this;
}
Date Date::operator--(int)
{
	Date tem(*this);
	*this -= 1;
	return tem;
}
bool Date::operator<(const Date& d)
{
	if (_year < d._year)
	{
		return true;
	}
	else if (_year == d._year)
	{
		if (_month < d._month)
		{
			return true;
		}
		else if (_month == d._month)
		{
			if (_day < d._day)
			{
				return true;
			}
		}
	}
	return false;
}
bool Date::operator==(const Date& d)
{
	return  _year == d._year
		&& _month == d._month
		&& _day == d._day;
}
bool Date::operator<=(const Date& d)
{
	return *this < d || *this == d;
}
bool Date::operator>(const Date& d)
{
	return !(*this <= d);
}
bool Date::operator>=(const Date& d)
{
	return *this > d || *this == d;
}
bool Date::operator!=(const Date& d)
{
	return !(*this==d);
}
int Date::operator-(const Date& d)
{
	Date max = *this;
	Date min = d;
	int flag = 1;
	if (*this < d)
	{
		max = d;
		min = *this;
	    flag = -1;
	}
	int n = 0;
	while (max != min)
	{
		min++;
		n++;
	}
	return n*flag;
}

6.2 Date.h

#pragma once
#include<iostream>
#include<assert.h>

using std::cout;
using std::cin;
using std::endl;

class Date
{
public:
    //构造函数
    Date(int year = 2020, int month = 1, int day = 11);
    void print();
    //析构、拷贝构造、赋值重载,可以不写,默认生成的就够用了
    //像Stack这样的才需要自己写。

    Date& operator+=(int day);
    Date  operator+(int day);

    Date& operator-=(int day);
    Date  operator-(int day);

    //++d->d.operator++(&d)
    //d++->d.operator++(&d,0)
    //int 参数不需要给实参,因为没用,它的作用是为了跟前置++构成函数重载。 
    Date& operator++();
    Date operator++(int);

    Date& operator--();
    Date operator--(int);

    bool operator<(const Date& d);
    bool operator>(const Date& d);
    bool operator<=(const Date& d);
    bool operator>=(const Date& d);
    bool operator==(const Date& d);
    bool operator!=(const Date& d);

    int operator-(const Date& d);

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


6.3 test.c

#include"date.h"

int main()
{
	Date d1(2022,6,26);
	d1.print();
	Date d2(2022,9,26);
	d2.print();
	d1 += 26;
	//d1 -= -26;
	//d1.print();
	Date d5=d1+(-26);
	//d1 += -26;
	//d1.print();
	Date d2(2022, 2, 28);//非法日期的测试
	//Date retd = --d1;
	//retd.print();
	//retd=d1--;
	//retd.print();
	//d1.print();

	cout << (d2 - d1) << endl;
	cout << (d1 - d2) << endl;
	return 0;
}

7. const成员函数

7.1  const 修饰的类成员函数称之为 const 成员函数 const 修饰类成员函数,实际修饰该成员函数 隐含的 this 指针 ,表明在该成员函数中 不能对类的任何成员进行修改。
7.2 
	void print() const
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

........
	Date d1(2022, 6, 25);
	d1.print();  //权限缩小
	const Date d2; 
	d2.print();

8. 取地址及const取地址操作符重载

8.1 基本用不到。了解他俩是默认成员函数就行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zhang丶&|!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值