class 类--------Date 日期类

本节主要来说说类与对象这个模块吧,类的关键词就是 class;前边接触到的C语言,是面向过程的一门语言注重的就是过程;而C++是基于面向对象的,关注的是对象,这也就意味着,从今天开始要注重一些C++语言的要点了,接下来一起学习吧!

一、类的定义(结构形式)

(一)首先来了解一下类的结构形式:

class A{
	//类体:由成员函数和成员变量组成
};  //类结束的分好不可以省略

如上述代码所展示的,定义了一个 A 类,A 就是类名,class 为定义类的关键词。

类的定义形式:

class A{
	public:
	    void show(){}
	protectedvoid Ket() {}
	private:
	    int a;
	    char b;
};

(二)类的访问限定符
在这里插入图片描述
1、public:公有
使用public 修饰的成员/成员函数 在类外可以直接访问
2、protected :保护
private :私有
使用protected / private 修饰的成员在类外不可以直接被访问
3、class 类的默认访问权限是 private ,struct 结构体为public

(三)类的特点
C++是一门面向对象的语言,面向对象有三大特性:封装、继承、多态
**封装:**是指将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现的细节,仅对外公开接口来和对象进行交互;封装本质上是一种管理。

类的作用域:
在类外定义成员,需要使用作用域解析符:: 来指明成员所属类域

class A{
	public:
	    void Show();
	private:
		int a;
		char b;
		int c;
};
//此处说明Show 是A 类的
void A::Show()
{
	cout<<a<<b<<b<<endl;
}

(四)类的成员变量/成员函数:

class A1{
	public:
		void Show(){}    //类的成员函数
	private:
		int _a;           //类的成员变量
};
class A2{
	public:
		void Show(){}     //仅有成员函数
};
class A3{};     //空类 ,这里要注意空类的大小不为0

类的大小:
空类的大小一般为1;
类的大小,实际上就是类中“成员变量”之和,但是要注意内存对齐
对齐数=编译器默认的一个对齐数与该成员大小的较小值

(五)类中this 指针
类中默认存在一个指针 this ,其类型是 *const;
只能在“成员函数”内部使用;
this 指针本质上是一个成员函数的形参,是一个隐含的指针形参,一般情况由编译器自动传递,不许用户设置。

注意看这两处代码:

class A{
public:
	void Show()
	{
		cout<<Show()<<endl;
	}
};
class B{
public:
	void Show(B* this)
	{
		cout<<Show<<endl;
	}
};

这两段代码看起来不太一样(有参无参),实质上这两段代码实现的功能一模一样,第一个代码中间 *this 是隐含的形参,因此写与不写都可以。

二、类的成员函数

(一)构造函数
首先定义一个Date 日期类:

class Date{
	public:
		Date (){}      //表示的是一个构造函数
	private:         //定义三个成员:年、月、日
		int _year;
		int _month;
		int _day;
};

构造函数时类中一个特殊的成员函数,它具有一下特性:
1.函数名与类名相同----Date;
2.无返回值,可以有参可以无参;
3.对象实例化时编译器会自动调用相应的构造函数;
4.构造函数可以重载;
5、如果在一个类中用户并没有定义构造函数,则系统会自动调用一个默认的构造函数(无参),但一旦用户自己定义了构造函数,系统将不会默认生成。

构造函数的分类:无参构造、有参构造在这里插入图片描述

(二)析构函数
析构函数与构造函数的功能正好相反,其表示形式是在构造函数函数名前加 ~

class Date {
public:
	Date()     //无参构造
	  {}
	~Date()    //析构函数
	  {}
private:
	int _year;
	int _month;
	int _day;
};

析构函数的特性:
1.析构函数在对象在销毁时会自动调用,完成资源清理;
2.析构函数在类名之前加上 ~;
3.无参无返回值;
4.一个类有且仅有一个析构函数,若未显示定义析构函数,系统会自动生成默认的析构函数;
5.在对象生命周期结束时,系统自动调用析构函数

(三)拷贝构造函数
拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(效率高),在用已存在的类类型对象创建新对象时由编译器自动调用。

class Date{
public:
	Date(int year=1900,int month=1,int day=1){
	_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;
};

构造函数也同样具有些特性:
1.拷贝构造函数是构造函数的一个重载形式------形参需为 const 类名&;
2.拷贝构造函数只能有一个形参 : const 类名 &;
3.若用户未定义,系统会默认生成一个拷贝构造函数;

(四)内部类

在一个类中定义一个新的类:

class A{
public:
	class B{           //在A 类中间定义了一个B 类
	public:
		void Show(){}
	private:
		int b;
};
private:
	int a;
};

另外要注意:

class Time {          // 定义一个时间类----时分秒
public:
	Time() {
		_hour = 17;
		_minute = 01;
		_second = 50;
	}
	/*Time(int hour = 17, int minute = 02, int second = 30) {
		_hour = hour;
		_minute = minute;
		_second = second;
	}*/
private:
	int _hour;
	int _minute;
	int _second;
};
class Date {          //定义一个日期类 Date---年月日
public:
	Date()
	{
		_year = 2020;
		_month = 10;
		_day = 24;
	}
private:
	int _year;
	int _month;
	int _day;
	Time t;            
};
void test()
{
	Date d1;
}
int main()
{
	test();
	return 0;
}

(五)操作符的重载

返回值类型 operator 操作符(参数列表)

注意:
1.不能进行重载的运算符:
.* 、:: 、sizeof 、?: 、.
2、要注意区分前置++/-- 与后置++/–

接下来主要以日期类 Date 来进行演示:

//首先,需要定义一个数组来存放每个月份所对应的天数:
int GetDate(int year, int month) {    //获取相应月份天数
		static int days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
		int day = days[month];
		if (month == 2) {
			//判断闰年
			if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
				day += 1;
			}
		}
		return day;
	} 

这里需要说明一下:
闰年,能够整除4但不能整除100,但是可以整除400

1.赋值运算符的重载:

Date& operator=(const Date& d) {
		if (&d != this) {
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this;
	}

在进行赋值运算符重载时候,需要判读是否是给自己赋值,若是直接返回,若不是在进行赋值操作
此处出现了前边提到过的this 指针,有兴趣的童鞋们下去可以自己试试哦。

2.+=运算符的重载
一个日期加上一个数(天数)再将加之后的结果返回,我们可以使用 & 引用类型来提高运算的效率。
在者,一个给定日期加上一个对应的天数要考虑到所加天数的正负—加上一个正数先直接相加;加上一个负数等于减去一个正数,直接调用-= 操作

在这里插入图片描述
同理,也需要考虑到月份/年份的溢出问题。

Date& operator+=(int day) {
		if (day < 0) {   //加一个负数 = 减一个正数
			return *this -= -day;
		}
		_day += day;   // 加法要考虑月份天数的进位问题
		while (_day > GetDate(_year, _month)) {
			_month++;         //判断是否溢出
			if (_month == 13) {
				_year++;
				_month = 1;
			}
		}
		return *this;
	}

3.-=运算符重载
+= 需要考虑进位问题
同理思考方式,-= 就需要考虑借位问题

Date&operator-=(int day) {
		if (day < 0) { // 减去一个负数 = 加上一个正数
			return *this += -day;
		}
		_day -= day;
		while (_day < 0) {    //考虑是否借位
			_month--;
			if (_month == 0) {
				--_year;
				_month = 12;
			}
			_day += GetDate(_year, _month);
		}
		return *this;
	}

4.==重载
判断日期相等---------》年、月、日 三者分别对应相等

bool operator==(const Date&d) {  // 判等
		return _year == d._year && _month == d._month && _day == d._day;
	}

5.>=重载

bool operator >=(const Date&d) {
    //return (operator==(d) || operator>(d));
		if (_year >= d._year) {
			return true;
		}
		else if (_year == d._year) {
			if (_month >= d._month) {
				return true;
			}
			else if (_month == d._month) {
				_day >= d._day;
			}
		}
		return false;
	}

要实现相应的<= 、<、>、!= 等等重载可以按照上例给出的>= 来进行书写,可以按照上例格式改符号,同样也可以灵活使用!(取反)操作来实现,童鞋们可以私下自己联系联系呀,最后我将给出本次的日期类相关操作代码,有跟我一起写代码的可以对比下,顺便看看我的代码存在的不足 :

代码模块:

class Date {
public:
	int GetDate(int year, int month) {    //获取相应月份天数
		static int days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
		int day = days[month];
		if (month == 2) {
			//判断闰年
			if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
				day += 1;
			}
		}
		return day;
	} 
	Date(int year = 2020, int month = 10, int day = 1) {  //全缺省构造
		_year = year;
		_month = month;
		_day = day;
	}
	//Date(const Date& d) {  //拷贝构造
	//	_year = d._year;
	//	_month = d._month;
	//	_day = d._day;
	//}
	~Date() { //析构函数
		cout << "~Date" << endl;
		_year = 0;
		_month = 0;
		_day = 0;
	}
	//赋值运算符重载
	Date& operator=(const Date& d) {
		if (&d != this) {
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this;
	}
	//运算符重载
	Date& operator+=(int day) {
		if (day < 0) {            //加一个负数 = 减一个正数
			return *this -= -day;
		}
		_day += day;            // 加法要考虑月份天数的进位问题
		while (_day > GetDate(_year, _month)) {
			_month++;
			if (_month == 13) {
				_year++;
				_month = 1;
			}
		}
		return *this;
	}
	Date&operator-=(int day) {
		if (day < 0) {                 // 减去一个负数 = 加上一个正数
			return *this += -day;
		}
		_day -= day;
		while (_day < 0) {
			_month--;
			if (_month == 0) {
				--_year;
				_month = 12;
			}
			_day += GetDate(_year, _month);
		}
		return *this;
	}
	Date operator+() {
		return *this += 1;
	}
	Date operator-() {
		return *this -= 1;
	}
	Date& operator++(){  //前置++    例:++i
		return *this += 1;
	}
	Date operator++(int) {    //后置++    例:i++
		Date tmp = *this;
		*this += 1;
		return tmp;
	}
	Date& operator--() {   //前置--    例:--i
		return *this -= 1;
	}
	Date operator--(int) {   //后置--   例:i--
		Date tmp = *this;
		*this -= 1;
		return tmp;
	}
	bool operator==(const Date&d) {  // 判等
		return _year == d._year && _month == d._month && _day == d._day;
	}
	bool operator!=(const Date&d) { //不等于
		//return !operator==(d);
		return (_year != _year) || (_month != d._month) || (_day != d._day);
	}
	bool operator >=(const Date&d) {
		//return (operator==(d) || operator>(d));
		if (_year >= d._year) {
			return true;
		}
		else if (_year == d._year) {
			if (_month >= d._month) {
				return true;
			}
			else if (_month == d._month) {
				_day >= d._day;
			}
		}
		return false;
	}
	bool 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) {
				_day > d._day;
			}
		}
		return false;
	}
	bool operator<(const Date&d) {
		return !operator>=(d);
	}
	bool operator<=(const Date&d) {
		//return !operator>(d);
		return (operator<(d) || operator==(d));
	}
	void PrintDate() {
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
//void test()
//{
//	Date d1(2020, 10, 24);
//	Date d2 = d1;
//	Date d3(d1);
//}
void test()
{
	Date d1(2020, 10, 12);
	d1 += 10;
	d1.PrintDate();
	d1 -= 20;
	d1.PrintDate();
	Date d2(2019, 10, 2);
	Date d3(2020, 10, 1);
	Date d4(2020, 10, 12);
	bool ret = d2 > d3;
	ret = d4 <= d2;
	ret = d3 >= d4;
}
int main()
{
	test();
	return 0;
}

运行解释:

在这里插入图片描述

定义 d1 时调用相应的构造函数
此时this --> d1
在这里插入图片描述

所有变量构造完成:
在这里插入图片描述

当所定义的 Date 类型的变量构造成功(调用拷贝构造函数)之后会自动调用析构函数,要注意析构函数的调用顺序与构造函数刚好相反---------------先构造的后析构

以上就是我本次想要分享的一些东西,希望感兴趣的童鞋可以自己练习练习,有些调试过程我没有完全展示出来,大家可以自己下去分步调试一下看看调用顺序,有问题的可以留言给我呀~~~~

biubiubiu~~

(博客内容全为小白原创,有问题的及时留言给我!)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值