类的6个默认成员函数
1、特殊成员函数
2、不写编译器会自动生成
构造函数
概念
构造函数是初始化对象,不是开空间
C语言中没有初始化,会出现随机值
六个特性
- 函数名与类名相同
- 无返回值
- 对象实例化 自动调用 该函数
- 构造函数可以重载
- 如没有显式定义的构造函数,编译器自动生成(隐式的无参构造函数);反之,则不会自动生成
注:①不显式写默认构造,对于内置类型成员变量,看编译器是否处理; 对于自定义类型成员变量才会调用它的 无参构造(不传参就可以调用的那个构造)
②默认构造函数包括:无参构造函数、全缺省构造函数、编译器默认生成的构造函数(隐式的无参构造函数)
6、内置类型成员变量在类中声明时可以给默认值
默认构造函数的意义
在两个栈实现一个队列,编译器给了初始化(在某种情况下有意义)
析构函数
概念
对象在销毁时自动调用析构函数,完成对象中的资源清理
C语言没有写Destroy,会造成内存泄漏
四个特性
- 析构函数名在类名前加~
- 无参数无返回值
- 一个类只能析构一个函数,析构函数不能重载
- 在生命周期结束时自动调用
- 析构函数内置类型不做处理,自定义类型会调用它的析构
- 析构函数可以显式写
小结
- 有资源清理(开空间)才需要析构函数;如Stack、Queue
- 有两种场景不需要显式析构,用默认生成的就OK了
- ①没有资源清理,如Date
- ②内置类型成员没有资源需要清理,剩下的都是自定义类型成员;如MyQueue
拷贝构造函数
概念
用同类型的对象拷贝初始化
三个特性
- 拷贝构造函数是构造函数的一个重载形式
- 拷贝构造函数的参数只有一个且必须是类类对象的引用,使用传值方式编译器直接报错,会引发无穷递归
- 未显式定义,编译器会默认生成拷贝构造函数
总结
- 一般情况下,不需要显式写析构函数,就不用写拷贝构造函数(值拷贝)
- 如果 内部有指针 或者 一些值指向资源,需要显式写析构函数释放,需要写构造完成深拷贝; 如Satck、Queue、List
赋值运算符重载
运算符重载
相等操作符重载函数(比较Date中的两个对象是否相等)
在全局中
在全局中写 operator== 函数,要屏蔽 Date类 中private,
那封装性如何保证?用 友元 和 重载成员函数 解决
这里讲的是重载成员函数,把 内置类型成员 公有,这样在全局中函数就能 访问 内置类型成员
在类中
注意点
在主函数中
this 和 *this 的区别
赋值运算符重载
赋值运算符重载格式
注意点
赋值运算符重载 和 拷贝构造函数 的区别
传值返回 和 传引用返回 的区别
传值返回 会生成当前对象的一个拷贝,拷贝一个临时对象
引用返回 生成某别名,出了作用域就销毁了
总结 虽然引用返回减少了拷贝,但出了函数作用域,返回对象还在才能用引用(在静态)
前置++ 和 后置++ 重载
const成员
含义
const修饰的是*this,本质上是改变this的类型
在哪用
- 运算符重载
- 不改变自身
取地址及const取地址操作符重载
不显式实现,编译器默认生成
日期类的实现
Date.h
#pragma once #include<iostream> #include<stdlib.h> using namespace std; class Date { // 友元函数,可以访问私有 friend ostream& operator<<(ostream& out, const Date& d); friend istream& operator>>(istream& in, Date& d); public: // 构造函数 Date(int year, int month, int day); // 打印 void Print(); // 运算符重载 // 实现</>,==就可以了,其他的复用(要建立栈帧,内联,不能声明和定义分离,在类里面定义就是内联) bool operator==(const Date& d) const; bool operator!=(const Date& d) const; bool operator>(const Date& d) const; bool operator>=(const Date& d) const; bool operator<(const Date& d) const; bool operator<=(const Date& d) const; static int GetMonthDay(int year, int month) { int GetMonthDayArr[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 }; if (month == 2 && (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) { return 29; } else return GetMonthDayArr[month]; } // 检查日期是否正确 bool checkDate() { if (_month < 1 || _month > 12 || _day <= 0 || _day > GetMonthDay(_year, _month)) return false; else return true; } // 日期 + 天数 Date& operator+=(int day); Date operator+(int day) const; // 日期 - 天数 Date& operator-=(int day); Date operator-(int day) const; // 前置++ Date& operator++(); // 后置++ Date operator++(int) const; // 前置-- Date& operator--(); // 后置-- Date operator--(int) const; // d1 - d2 int operator-(const Date& d) const; private: int _year; int _month; int _day; }; // 流插入重载 ostream& operator<<(ostream& out, const Date& d); // 流提取重载 istream& operator>>(istream& in, Date& d);
Date.cpp
#define _CRT_SECURE_NO_WARNINGS 1 #define _CRT_SECURE_NO_WARNINGS 1 #include"Date.h" Date::Date(int year, int month, int day) { //cout << "Date(int year, int month, int day)" << endl; _year = year; _month = month; _day = day; } void Date::Print() { cout << _year << "-" << _month << "-" << _day << endl; } bool Date::operator==(const Date& d) const { return this->_year == d._year && this->_month == d._month && this->_day == d._day; } bool Date::operator!=(const Date& d) const { return !(*this == d); } bool Date::operator>(const Date& d) const { if (this->_year > d._year) return true; else if (this->_year == d._year && this->_month > d._month) return true; else if (this->_year == d._year && this->_month == d._month && this->_day > d._day) return true; return false; } bool Date::operator>=(const Date& d) const { return *this > d || *this == d; } bool Date::operator<(const Date& d) const { return !(*this >= d); } bool Date::operator<=(const Date& d) const { return !(*this > d); } // 日期 + 天数 Date& Date::operator+=(int day) { if (day < 0) return *this -= -day; _day += day; while (_day > GetMonthDay(_year, _month)) { _day -= GetMonthDay(_year, _month); ++_month; if (_month == 13) { ++_year; _month = 1; } } return *this; } Date Date::operator+(int day) const { Date tmp = *this; tmp += day; return tmp; } Date& Date::operator-=(int day) { if (day < 0) return *this += -day; _day -= day; while (_day <= 0) { --_month; if (_month == 0) { _month = 12; --_year; } _day += GetMonthDay(_year, _month); } return *this; } Date Date::operator-(int day) const { Date tmp = *this; tmp -= day; return tmp; } // 前置++ Date& Date::operator++() { *this += 1; return *this; } // 后置++ Date Date::operator++(int) const { Date tmp = *this; tmp += 1; return tmp; } // 前置-- Date& Date::operator--() { *this -= 1; return *this; } // 后置-- Date Date::operator--(int) const { Date tmp = *this; tmp -= 1; return tmp; } int Date::operator-(const Date& d) const { Date max = *this; Date min = d; int n = 0, flag = 1; if (*this < d) { max = d; min = *this; flag = -1; } while (min != max) { ++min; ++n; } return flag * n; } //ostream& Date::operator<<(ostream& out) //{ // out << _year << "-" << _month << "-" << _day << endl; // return out; //} ostream& operator<<(ostream& out, const Date& d) { out << d._year << "-" << d._month << "-" << d._day << endl; return out; } istream& operator>>(istream& in, Date& d) { cout << "请输入年、月、日:"; in >> d._year >> d._month >> d._day; if (!d.checkDate()) { cout << "输入的日期无效,请重新输入。" << endl; in.clear(); // 清除错误标志 in.ignore(numeric_limits<streamsize>::max(), '\n'); // 忽略错误输入直到下一个换行符 return in; } return in; }
Test.cpp
#define _CRT_SECURE_NO_WARNINGS 1 #include"Date.h" void test1() { Date d1(2024, 9, 26); Date d2(2024, 9, 26); bool ret1 = d1 > d2; bool ret2 = d1 >= d2; bool ret3 = d1 < d2; bool ret4 = d1 <= d2; bool ret5 = d1 == d2; bool ret6 = d1 != d2; cout << ret1 << endl; cout << ret2 << endl; cout << ret3 << endl; cout << ret4 << endl; cout << ret5 << endl; cout << ret6 << endl; } void test2() { Date d1(2024, 9, 26); Date d2(2024, 9, 26); // += // 11-15 Date tmp = d1 -= -100; d1.Print(); //tmp.Print(); + //Date tmp2 = d2 + 50; //d2.Print(); // 9-26 //tmp2.Print(); // 11-15 //Date d3(2024, 9, 26); //Date d4(2024, 9, 26); -= //8-7 //Date tmp3 = d3 -= 50; //d3.Print(); //tmp3.Print(); - //Date tmp4 = d4 - 50; //d4.Print(); //tmp4.Print(); } void test3() { Date d1(2024, 9, 26); Date d2(2024, 9, 26); Date tmp = --d1; d1.Print(); tmp.Print(); Date tmp2 = d2--; d2.Print(); tmp2.Print(); } void test4() { Date d1(2024, 9, 26); Date d2(2024, 10, 1); int ret = d1 - d2; cout << ret << endl; } void test5() { // 流插入和流提取 / 内置类型 直接用,为什么? //cout << "1"; //printf("2"); //cout << "3"; //printf("4"); Date d1(2024, 9, 26); //d1 << cout; // 类中 cout << d1; // 全局 } void test6() { Date d1(2024,9,27); Date d2(2024,10,1); cin >> d1 >> d2; cout << d1 << d2; } void test7() { const Date d1(2024, 9, 27); Date d2(2024, 9, 27); bool d3 = d1 > d2; Date d4 = d1 - 10; } int main() { //test1(); //test2(); //test3(); //test4(); //test5(); //test6(); test7(); }