默认函数
本文中狭义定义为:编译器默认生成的函数,在用户不去定义时自动生成且隐藏。若用户去定义,则不在自动生成。
构造函数
作用:初始化对象。
特征:
- 函数名与类名相同。
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.若想自定义拷贝构造,拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用。
// 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;
}