1.类的6个默认成员函数
如果一个类中什么成员都没有,简称为空类。空类中什么都没有吗?并不是的,任何一个类在我们不写的情 况下,都会自动生成下面6个默认成员函数。
2.构造函数
构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,保证每个数据成员都有一个合适的初始值,并且在对象的生命周期内只调用一次。
class Date
{
public:Date(int year = 0,int month = 0,int day = 0)//构造函数(全缺省){_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, 2, 15);d1.Print();Date d2;d2.Print();return 0;
}
构造函数的特性:
- 函数名与类名相同。
- 无返回值。
- 对象实例化时编译器自动调用对应的构造函数。
- 构造函数可以重载。
- 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成。编译器自动生成的默认构造函数不会初始化内置类型(基本类型),如:int , char , double等。但是会初始化我们的自定义类型。如我们用class,struct等定义的类型。
- 无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。注意:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认成员函数。
哪些属于默认构造函数?
- 我们没写编译器自己生成的
- 我们写的无参的
- 我们写的全缺省的
3.析构函数
析构函数:与构造函数功能相反,析构函数不是完成对象的销毁,局部对象销毁工作是由编译器完成的。而 对象在销毁时会自动调用析构函数,完成类的一些资源清理工作。
特性:析构函数是特殊的成员函数。其特征如下:
- 析构函数名是在类名前加上字符 ~。
- 无参数无返回值。
- 一个类有且只有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。
- 对象生命周期结束时,C++编译系统系统自动调用析构函数。
- 析构函数的调用也符合先进后出
4.拷贝构造函数
拷贝构造函数也是特殊的成员函数,其特征如下:
- 拷贝构造函数是构造函数的一个重载形式。
- 拷贝构造函数的参数只有一个且必须使用引用传参,使用传值方式会引发无穷递归调用。
- 若未显示定义,系统生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷,贝这种拷贝我们叫做浅拷贝或者值拷贝。
从此以后注意,函数传参,自定义类型的对象,一般推荐引用传参。如果还要继续使用传值传参,也不是不可以,但是每次调用都会调用拷贝构造
5.运算符重载
C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
函数名字为:关键字operator后面接需要重载的运算符符号。
函数原型:返回值类型 operator操作符(参数列表)
注意:
1.不能通过连接其他符号来创建新的操作符:比如operator@
2.重载操作符必须有一个类类型或者枚举类型的操作数
3.用于内置类型的操作符,其含义不能改变,例如:内置的整型+,不能改变其含义
4.作为类成员的运算符重载函数时,操作符有一个默认的形参this,限定为第一个形参
5…* 、:: 、sizeof 、?: 、. 注意这5个运算符不能重载。
6.&重载和const&重载
这两个默认成员函数一般不用重新定义 ,编译器默认会生成。
7.练习编写默认成员函数
我们以实现一个日期类为例,练习一下
Date.h
#pragma once
#include <iostream>using std::cin;
using std::cout;
using std::endl;bool IsLeapYear(const int year);
int GetMonthDay(const int year, const int month);
class Date
{
public:Date(int year = 0, int month = 1, int day = 1){_year = year;_month = month;_day = day;}//Date类成员只有三个int,不需要写析构函数和拷贝构造Date& operator=(const Date& d){_year = d._year;_month = d._month;_day = d._day;return *this; //这个函数之所以要有返回值,是为了解决 d3 = d2 = d1 这种情况}&重载和const&重载 这两个默认成员函数绝大多数情况下不需要自己写//Date* operator&()//{// return this;//}//const Date* operator&()const//{// return this;//}//日期的比较函数 这几个函数都比较短,直接定义在类里面了,在类里面定义的函数默认是内联函数bool operator>(const Date& d)const{if (_year > d._year)return true;if (_year == d._year && _month > d._month)return true;if (_year == d._year && _month == d._month && _day > d._day)return true;return false;}bool operator==(const Date& d)const{return _year == d._year&& _month == d._month&& _day == d._day;}bool operator<(const Date& d)const{if (*this > d || *this == d)return false;return true;}bool operator>=(const Date& d)const{if (*this < d)return false;return true;}bool operator<=(const Date& d)const{if (*this > d)return false;return true;}bool operator!=(const Date& d)const{if (*this == d)return false;return true;}//日期+-天数Date& operator+=(int day);Date operator+(int day)const;Date& operator-=(int day);Date operator-(int day)const;//日期前置++--和后置++--//为了区分前置和后置,有这样一个约定,在重载后置++--多一个int参数//由于前置++返回的是++后的值,可以传引用返回,而后置返回的是++之前的值,需要先创建一个临时变量保存++之前的值,在传值返回//前置++--相比于后置少了两次拷贝构造,效率稍微高一些Date& operator++();Date operator++(int);Date& operator--();Date operator--(int);//两个日期差多少天int operator-(const Date& d)const;void Print()const //这个const修饰的是this指针,使this指针指向的内容不能被修改的{cout << _year << "-" << _month << "-" << _day << endl;}
private:int _year;int _month;int _day;
};
Date.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include "Date.h"bool IsLeapYear(const int year)
{if (year % 4 == 0 && year % 100 != 0)return true;if (year % 400 == 0)return true;return false;
}
int GetMonthDay(const int year, const int month)
{const static int arr[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };int days = arr[month];if (IsLeapYear(year) && month == 2)days += 1;return days;
}
Date& Date::operator+=(int day)
{while (day--){_day++;if (_day > GetMonthDay(_year, _month)){_month++;_day = 1;if (_month > 12){_year++;_month = 1;}}}return *this;
}Date Date::operator+(int day)const
{//我们知道i+12不影响i的值,所以为了不改变原来的Date的值,我们先拷贝构造一个,并且这里不能传引用返回,因为copy是局部变量Date copy = *this;copy += day;return copy;
}Date& Date::operator-=(int day)
{while (day--){_day--;if (_day == 0){_month--;if (_month == 0){_year--;_month = 12;}_day = GetMonthDay(_year, _month);}}return *this;
}Date Date::operator-(int day)const
{Date copy = *this;copy -= day;return copy;
}Date& Date::operator++()
{*this += 1;return *this;
}Date Date::operator++(int)
{Date copy = *this;*this += 1;return copy;
}Date& Date::operator--()
{*this -= 1;return *this;
}
Date Date::operator--(int)
{Date copy = *this;*this -= 1;return copy;
}int Date::operator-(const Date& d)const
{//让小的日期++,直到和大的日期相等为止int count = 0;int flag = -1;Date min = *this;Date max = d;if (min > max){min = d;max = *this;flag = 1;}while (min < max){min++;count++;}return flag * count;
}