C++ 类的默认函数

默认函数

本文中狭义定义为:编译器默认生成的函数,在用户不去定义时自动生成且隐藏。若用户去定义,则不在自动生成。

构造函数

作用:初始化对象。
特征:

  1. 函数名与类名相同。
    2. 无返回值。
    3. 对象实例化时编译器自动调用对应的构造函数。
    4. 构造函数可以重载。

值得注意:
1.使用默认生成的构造函数初始化对象,初始化对象的值依旧是随机值。
原因:C++把类型分成内置类型(基本类型)和自定义类型。内置类型就是语言提供的数据类型,如:int/char…,自定义类型就是我们定义的类型。
默认构造函数不对默认类型起作用。而自定义类型在最终也是由基本类型构成,故自定义类型里的值也没有被初始化。
解决:在成员变量声明部分“赋值”(实际上类似于缺省值)。

class Date
{
private:
 int _year = 1970;
 int _month = 1;
 int _day = 1;
 }

析构函数

作用:完成对象内容销毁

特征如下:1. 析构函数名是在类名前加上字符 ~。
2. 无参数无返回值类型。
3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。
4. 对象生命周期结束时,C++编译系统系统自动调用析构函数

值得注意: 1.析构函数不能重载。
2.注意对象的声明何时结束。
3.若类中有自定义类型成员变量,则会调用自定义成员本身的析构函数
4.利用 malloc 等申请的空间资源,必须自己去定义对应的析构函数才能达到目的。(malloc 申请的空间在堆里,不去free()不会释放)

拷贝构造

作用:用于创建于已存在对象完全相同的对象。
特征
拷贝构造函数也是特殊的成员函数,其特征如下:

  1. 拷贝构造函数是构造函数的一个重载形式。
  2. 若未显式定义,编译器会生成默认的拷贝构造函数。(只能浅拷贝)

值得注意:

1.什么是时候会用到拷贝构造函数?
答: 使用已存在对象创建新对象
函数参数类型为类类型对象
函数返回值类型为类类型对象

2.若想自定义拷贝构造,拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用。

// Date(const Date& d)   // 正确写法
 Date(const Date& d)   // 错误写法

3.浅拷贝和深拷贝的区别:在这里插入图片描述

运算符重载

(运算符是一种具有特殊函数名的函数)

作用:增强代码可读性。
举例说明作用:其实 cout << x 打印,是对 << 进行了函数重载,使得x是char 或者 int 都能被打印。
特性:
1.赋值运算符只能重载成类的成员函数不能重载成全局函数
(赋值运算符如果不显式实现,编译器会生成一个默认的。此时用户再在类外自己实现一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的成员函数。)

2.函数名字为:关键字operator后面接需要重载的运算符符号。
函数原型:返回值类型 operator操作符(参数列表)

3.用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝。(内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。)

注意:
1.不能通过连接其他符号来创建新的操作符:比如operator@
(一个运算符最多只有左右两个操作对象,重载一个操作符参数部分一般情况分为两种, 第一种:只有一个参数,此时this指针必为重载所在类对象的指针。 第二种:两个参数,前一个参数代表操作符左边的对象或变量,后一个操作符代表操作符右边的成员或变量,左右必有一个为重载所在类的对象。)
2.重载操作符必须有一个类类型参数
3.用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不能改变其含义
作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this
.* :: sizeof ?: . 注意以上5个运算符不能重载。这个经常在笔试选择题中出
现。

定义一个简单的日期类

类功能:
1 以年月日的形式表示日期;
2 可直接用<< 打印日期
3 可直接用 + - 实现日期与天数的加减
4 可直接对日期直接进行比较

.h 文件声明(文件名为“标头”):

#pragma once
#include <iostream>
#include<assert.h>
#include<ostream> 
using std::cout;
using std::cin;
using std::endl;
using std::ostream; //ostream 是一个类 cout是该类的一个对象




class Date
{
	friend ostream& operator<<(ostream& out ,Date& date);  //方便打印 ,了解ostream
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;	
		_day = day;
	}

	bool operator<(const Date& date);
	bool operator<=(const Date& date);
	bool operator>(const Date& date);
	bool operator>=(const Date& date);
	bool operator==(const Date& date);

	Date& operator+=(int day);
	Date operator+(int day) const;   
	Date& operator-=(int day);
	Date operator-(int day) const;
	
	bool isLeapYear(int year); 
	int GetMonthDay(int year, int month);

	void Print()
	{
		cout << _year << "年" << _month <<"月" << _day <<"月" << endl;
	}
private:
	int _year = 1;
	int _month = 1;
	int _day = 1;
};

.cpp 文件定义:

在这里插入代码片
#include"标头.h"



bool Date::isLeapYear(int year)
{
	bool ret = false;
	if (year % 4 == 0)
	{
		ret = true;
		if (year % 100 == 0)
		{
			ret = false;
			if (year % 400 == 0)
			{	 
				ret = true;
				return ret;
			}
		}
	}
	return ret;
}



bool Date::operator<(const Date& date) 
{
	if (
		(_year < date._year)
		|| (_year == date._year && _month < date._month)
		|| (_year == date._year && _month == date._month && _day < date._day))
	{
		return  true; 
	}
	else
	{
		return false;
	}
}



bool Date::operator<=(const Date& date)
{
	return ((*this < date) || (*this == date));

}



bool Date::operator>(const Date& date)
{
	return (!(*this < date)) && (!(*this == date));
}



bool Date::operator>=(const Date& date)
{
	return (!(*this < date));
}



bool Date::operator==(const Date& date)
{
	return (_day == date._day 
		&& _year == date._year
		&& _month == date._month);
}



int Date::GetMonthDay(int year, int month)
{
	int monthDay[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
	if (month == 2 )
	{
		if (Date::isLeapYear(year))
		{
			return 29;
		}
		else
		{
			return 28;
		}
	}
	else
	{
		return monthDay[month];
	}
}



Date& Date::operator+=(int day)
{
	_day = _day + day;
	while (_day > Date::GetMonthDay(_year, _month)) //先考虑day不为负数的情况吧
	{
		_day = _day - GetMonthDay(_year, _month);
		_month = _month + 1; 
		if (_month > 12 )
		{
			_month = 1;
			_year = _year + 1;
		}
	}
	return *this;
}



Date Date::operator+(int day) const 
{
	Date tmp = *this;
	tmp += day;
	return tmp;
}



Date& Date::operator-=(int day)
{
	_day = _day - day;
	int monthTmp = _month - 1; //因为计算方法是 _day - day + month(要加前一个月的天数)
	if (monthTmp == 0 )
	{
		monthTmp = 12;
	}
	while (_day <= 0)
	{
		_day = _day + Date::GetMonthDay(_year, monthTmp);
		monthTmp = monthTmp - 1;
		if (monthTmp == 0)
		{
			monthTmp = 12;
			_year = _year - 1;
		}
	}
	_month = monthTmp + 1;
	return *this;
}



Date Date::operator-(int day) const
{
	Date tmp = *this;
	tmp -= day;
	return tmp; 
}



ostream& operator<<(ostream& out, Date& date)
{
	out << date._year << "年" << date._month << "月" << date._day << "日" << endl;
	return out;
}

  • 15
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

弦化

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

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

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

打赏作者

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

抵扣说明:

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

余额充值