
🔥个人主页:艾莉丝努力练剑 ❄专栏传送门:《C语言》、《数据结构与算法》、C语言刷题12天IO强训、LeetCode代码强化刷题、C/C++干货分享&学习过程记录 🍉学习方向:C/C++方向 ⭐️人生格言:为天地立心,为生民立命,为往圣继绝学,为万世开太平


前言:本专栏记录了博主C++从初阶到高阶完整的学习历程,会发布一些博主学习的感悟、碰到的问题、重要的知识点,和大家一起探索C++这门程序语言的奥秘。这个专栏将记录博主C++语法、高阶数据结构、STL的学习过程,正所谓“万丈高楼平地起”,我们话不多说,继续进行C++阶段的学习。本文我们继续进入到类的深层,学习类的默认成员函数。
C++的两个参考文档:
老朋友(非官方文档):cplusplus 官方文档(同步更新):cppreference
在上篇文章当中,我们已经介绍了(C++11之前)6个类的默认成员函数中最为重要的前4个默认成员函数中的构造函数和析构函数,本文我们在学习了构造函数和析构函数的基础上,继续学习剩下的两个默认成员函数:拷贝构造和赋值拷贝——赋值运算符重载。
1、对象生命周期结束时,系统自动调用析构函数。
2、拷贝构造(构造的一种特殊)就是复制构造,拷贝是Copy的音译,复制是意译,可以这样理解,构造函数的一个重载。
3、第一个参数必须是当前类类型对象的引用,否则语法上会构成“无穷递归”,这个我们上篇文章给了一张非常形象的图,大家可以回去再看一下哈,注意内置类型都不大(不超过八个字节),自定义类型很复杂(拷贝都要去调用生成拷贝构造)。
4、传值传参调用拷贝构造。
5、自定义类型,完成传参再去调用,传参要拷贝构造,再调用函数。
6、每次调用拷贝构造函数之前要传值传参(是一种拷贝,又形成一个新的拷贝构造,就导致了“无限递归”,传值传参要递归调用,递归调用就要调自己,如果每次都没调用到,就会不断地拷贝),因此我们要引用传参(形参是实参的别名,不用拷贝),也可以用指针,但是我们基本上不回去用指针,因为指针一用就变成普通的构造了,用指针可以是可以,但是用起来逻辑很怪,而且还要取地址,我们用引用传参更符合使用习惯和场景。
7、传引用传参,建议不改变加const:
(1)权限缩小;(2)权限可以平移。
不加会存在权限放大,比如从只读变成可读可写。
8、浅拷贝(值拷贝):对于日期类刚刚好,对于栈就不行了:
(1)一个东西修改会影响另一个对象;(2)析构时,会释放两次空间(比如_a这一块空间已经释放过一次,为空,第二次变野就不能再释放了,这里相当于同一块空间释放两次)。
深拷贝:更深层次的拷贝——不仅仅是对成员进行拷贝,还要对指向资源空间数据进行处理,
如下图所示——

我们新开辟一块空间,这样既不会让一个对象修改影响另一个对象,也不会释放两次空间:

st1、st2各自有各自的空间,地址不同。
我们之后介绍STL部分的内容的时候会再结合场景讲深拷贝的。
9、日期类不用写拷贝构造(编译器自动生成的就够用了,不用显式写);
栈必须自己生成拷贝构造——当然,MyQueue也不需要显式写。
10、显式实现了析构并释放资源,就需要显式写拷贝构造,否则就不需要。
11、传值返回、传引用返回(没有调用拷贝,返回的是别名)——如果是局部对象就会有问题——返回了一个野引用,如果是静态的,就用传引用(可以提高效率),总之,我们能保证正确的前提下就用传引用(先保证正确性再保证性能——传引用返回性能高)。
1、日期类不支持+、-(C++设计重载来解决这个问题)。
2、之前学习的函数重载(参数不同的同名函数)和这个赋值运算符重载没有实质关系,这个博主也可以打个比方,比如两个历史人物,所处时代差不多、名字又很相近,比如那些胡诌历史的说评书匠,说这个隋唐的时候有员大将——“平辽王”——薛仁贵,不懂的人可能会和另一个民间传说中的人物薛平贵或者隋朝末年的大将薛仁杲扯到一起去,不了解中国历史的人真的有可能分不清,加上说书人一戏说,就相去甚远了,薛仁贵和薛仁杲没有实质关系,薛仁贵和薛平贵也没有实质关系,这个跟函数重载、赋值运算符重载没有实质关系同理。
3、左侧传第一个,右侧传第二个(乘、等不受影响)。
4、汇编cmp就是compare“比较”的意思。
5、如下图所示——

6、 参数个数应该和运算对象一样多(this指针)。
7、优先级和结合性应和内置类型保持一致。
8、重载运算符/操作符(运算符 = 操作符)。
9、至少得有一个类类型参数。
10、重载operator+(日期 + 日期没意义,日期 + 天数有意义)有意义,*没意义。
1、赋值拷贝和拷贝构造要注意区分,这是已经存在的对象,和拷贝构造类似但不一样。
2、日期类不需要写赋值运算符重载,MyQueue也不需要(调用栈的,自定义类型Stack成员)。
3、写static,会放在静态区,月份天数长期不变,加static就不会建立栈帧了。
4、让拷贝多的复制拷贝少的。
5、如下图所示——

代码实现如下所示——

实际上这个红框框里面不用具体什么值,只要是个整型就行,0也行,1也行,主要是为了区分,构成重载,给后置++强行加了一个int形参,后置实参传什么都行(得是整型),主要是为了区分,它不接收,自定义类型尽可能用前置(拷贝少,效率高),后置有两个拷贝。

如果一个构造函数的第一个参数是自身类类型的引用,并且任何额外的参数都有默认值,则此构造函数也叫做拷贝构造函数,也就是说拷贝构造是一个特殊的构造函数。
拷贝构造主要有以下六个特点,具体如下所示——

无穷递归——

拷贝构造部分代码演示如下——
#include<iostream>
using namespace std;
class Stack
{
public:
Stack(int n)
{}
};
class MyQueue
{
public:
//初始化列表
MyQueue()
:_pushst(4)
,_popst(4)
{ }
private:
Stack _pushst;
Stack _popst;
};
int main()
{
MyQueue q;
return 0;
}
class Date
{
public:
Date(int year = 1, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
//Date d4(d3);
Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
//自定义类型,传值传参要调用拷贝构造
//void Func(const Date& d)
void Func(Date d)
{ }
typedef int STDataType;
class Stack
{
public:
Stack(int n = 4)
{
_a = (STDataType*)malloc(sizeof(STDataType) * n);
if (nullptr == _a)
{
perror("malloc error");
return;
}
_capacity = n;
_top = 0;
}
//Stack st2(st1);
Stack(const Stack& s)
{
_a = s._a;
_capacity = s._capacity;
_top = s._top;
}
Stack(const Stack& s)
{
_a = (STDataType*)malloc(sizeof(STDataType)* s._capacity);
if (_a == NULL)
{
perror("malloc fail");
return;
}
memcpy(_a, s._a, s._top * sizeof(STDataType));
_capacity = s._capacity;
_top = s._top;
}
void Push(STDataType x)
{
if (_top == _capacity)
{
int newcapacity = _capacity * 2;
STDataType* tmp = (STDataType*)realloc(_a, newcapacity *
sizeof(STDataType));
if (tmp == NULL)
{
perror("realloc fail");
return;
}
_a = tmp;
_capacity = newcapacity;
}
_a[_top++] = x;
}
~Stack()
{
cout << "~Stack()" << endl;
free(_a);
_a = nullptr;
_top = _capacity = 0;
}
private:
STDataType* _a;
size_t _capacity;
size_t _top;
};
class MyQueue
{
private:
Stack _pushst;
Stack _popst;
};
int main()
{
Date d1(2025, 8, 1);
//拷贝构造
Date d2(d1);
const Date d3(2025, 8, 1);
Date d4(d3);
Func(d1);
//////////////////////////////////////////////////////////////
Stack st1;
st1.Push(1);
st1.Push(2);
st1.Push(3);
Stack st2(st1);
MyQueue q1;
MyQueue q2(q1);
return 0;
}
int& func2()
{
int x = 1;
return x;
}
Stack& Func3()
{
Stack st;
return st;
}
int main()
{
int ret1 = func2();
cout << ret1 << endl;
Stack ret2 = Func3();
//Stack ret2 = (Func3());
Stack st3;
//以下都是调用拷贝构造
Stack st4(st3);
Stack st5 = st3;
return 0;
}赋值拷贝和拷贝构造要注意区分,这是已经存在的对象,和拷贝构造类似但不一样。
运算符重载的概念:
1、当运算符被用于类类型的对象时,C++语言允许我们通过运算符重载的形式指定新的含义:
C++规定类类型对象使用运算符时,必须转换成调用对应运算符重载,若没有对应的运算符重载,则会编译报错。
2、运算符重载是具有特殊名字的函数,其名字是由operator和后面要定义的运算符共同构成:
和其他函数一样,它也具有其返回类型和参数列表以及函数体。
3、重载运算符函数的参数个数和该运算符作用的运算对象数量一样多:
一元运算符有一个参数,二元运算符有两个参数,二元运算符的左侧运算对象传给第一个参数,右侧运算对象传给第二个参数。
4、如果一个重载运算符函数是成员函数,则它的第一个运算对象默认传给隐式的this指针,因此运算符重载作为成员函数时,参数比运算对象少一个。
5、运算符重载以后,其优先级和结合性与对应的内置类型运算符保持一致。
6、不能通过连接语法中没有的符号来创建新的操作符:比如operator@。
7、如下图所示——

大家要注意,以上图中的5个运算符不能重载(大家记一下,选择题常考)。
8、重载操作符至少有一个类类型参数,不能通过运算符重载改变内置类型对象的含义,如:
int operator+(int x, int y)9、一个类需要重载哪些运算符,是看哪些运算符重载后有意义,比如Date类重载operator-就有意 义,但是重载operator+就没有意义。
10、重载++运算符时,有前置++和后置++,运算符重载函数名都是operator++,无法很好的区分。 C++规定,后置++重载时,增加一个int形参,跟前置++构成函数重载,方便区分。
11、重载<<和>>时,需要重载为全局函数,因为重载为成员函数,this指针默认抢占了第一个形参位置,第一个形参位置是左侧运算对象,调用时就变成了——
对象<<cout不符合使用习惯,可读性也不好。重载为全局函数把ostream/istream放到第一个形参位置就可以了,第二个形参位置当类类型对象。
赋值运算符重载的概念:
赋值运算符重载是一个默认成员函数,用于完成两个已经存在的对象直接的拷贝赋值,这里要注意跟拷贝构造区分,拷贝构造用于一个对象拷贝初始化给另一个要创建的对象。
1、赋值运算符重载是一个运算符重载,规定必须重载为成员函数。赋值运算重载的参数建议写成 const当前类类型引用,否则会传值传参会有拷贝。
2、有返回值,且建议写成当前类类型引用,引用返回可以提高效率,有返回值目的是为了支持连续赋值场景——赋值运算符重载为了支持连续赋值,有返回值;
3、没有显式实现时,编译器会自动生成一个默认赋值运算符重载,默认赋值运算符重载行为跟默认拷贝构造函数类似,对内置类型成员变量会完成浅拷贝(即值拷贝:一个字节一个字节的拷贝),对自定义类型成员变量会调用他的赋值重载函数。
4、(1)像Date类这样的类的成员变量全是内置类型且没有指向什么资源,编译器自动生成的赋值运算符重载就可以完成需要的拷贝,所以不需要我们显示实现赋值运算符重载;
(2)像Stack这样的类,虽然也都是内置类型,但是_a指向了资源,编译器自动生成的赋值运算符重载完成的浅拷贝(值拷贝)不符合我 们的需求,所以需要我们自己实现深拷贝(对指向的资源也进行拷贝);
(3)像MyQueue这样的类型内部 主要是自定义类型Stack成员,编译器自动生成的赋值运算符重载会调用Stack的赋值运算符重载, 也不需要我们显示实现MyQueue的赋值运算符重载;
补充——小技巧:
如果一个类显示实现了析构并释放资源,那么他就需要显示写赋值运算符重载,否则就不需要。
代码演示如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class Date
{
public:
Date(int year = 1, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
Date(const Date& d)
{
cout << " Date(const Date& d)" << endl;
_year = d._year;
_month = d._month;
_day = d._day;
}
// 传引用返回减少拷贝
// d1 = d2;
Date& operator=(const Date& d)
{
// 不要检查自己给自己赋值的情况
if (this != &d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
// d1 = d2表达式的返回对象应该为d1,也就是*this
return *this;
}
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2024, 7, 5);
Date d2(d1);
Date d3(2024, 7, 6);
d1 = d3;
// 需要注意这里是拷贝构造,不是赋值重载
// 请牢牢记住赋值重载完成两个已经存在的对象直接的拷贝赋值
// 而拷贝构造用于一个对象拷贝初始化给另一个要创建的对象
Date d4 = d1;
return 0;
}运行一下——

日期类不需要写赋值运算符重载,MyQueue也不需要(调用栈的,自定义类型Stack成员)。
这一段的代码量非常大,为了不占用太多【正文】的内容,博主会把Date日期类实现的代码放到结尾的【本文所涉及的所有代码的完整实现】中,正文就只放代码截图啦!



是不是很长,哈哈哈,这个要是放在正文就有点水字数了。
运行一下程序——

以下是补充的内容,大家可以不看,博主在上篇文章——【C/C++】类和对象(中):(一)类的默认成员函数——构造函数,析构函数里就讲过:

因此这个补充内容部分我们只是稍作了解,重点掌握前4个默认成员函数!
1、我们将const修饰的成员函数称之为const成员函数,const修饰成员函数被放到成员函数参数列表的后面。
2、const实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。const修饰Date类的Print成员函数,Print隐含的this指针由
Date* const this变成了:
const Date* const thisconst成员函数的代码演示如下——
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class Date
{
public:
Date(int year = 1, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
// void Print(const Date* const this) const
void Print() const
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
//这里非const对象也可以调用const成员函数是一种权限的缩小
Date d1(2024, 7, 5);
d1.Print();
const Date d2(2024, 8, 5);
d2.Print();
return 0;
}一句话总结干货——
1、不修改成员变量的成员函数都应该加上const;
2、const不能随便加,加了成员函数的成员变量就不能改变;
3、加了const,const对象和普通对象都可以调用const成员函数(权限不能放大,但可以平移或者缩小);
4、初始化的时候编译器会特殊处理,此时不具有const属性,初始化之后,才具有const属性;
5、不用加const的几种情况——
(1)const调构造函数; (2)const调析构函数; (3)拷贝构造、赋值重载(改变自己,不考虑用const)。
取地址运算符重载分为普通取地址运算符重载和const取地址运算符重载,一般来说,这两个函数编译器自动生成的就够我们用了,不需要去显示实现。除非是一些很特殊的场景,比如我们不想让别人取到当前类对象的地址,就可以自己实现一份,胡乱返回一个地址。
取地址运算符重载的代码演示如下——
#define _CRT_SECURE_NO_WARNINGS 1
class Date
{
public:
Date* operator&()
{
return this;
// return nullptr;
}
const Date* operator&()const
{
return this;
// return nullptr;
}
private:
int _year; // 年
int _month; // 月
int _day; // 日
};【C/C++】类和对象(中):(一)类的默认成员函数——构造函数,析构函数
【C/C++】类和对象(上):(二)实例化——类实例化出对象,对象大小,this指针,对比C++/C两种语言实现Stack
【C/C++】类和对象(上):(一)类和结构体,命名规范——两大规范,新的作用域——类域
结语:本文内容到这里就全部结束了, 本文我们在上一篇文章的基础上,继续学习了类和对象更深层次的内容,类的默认成员函数,拷贝构造、运算符重载赋值拷贝等重要的知识点,从现在一直到学习到模版初阶学完之后,都是些晦涩的概念,还不太能用得起来,到后面我们就能像之前学习数据结构那样,结合起来介绍。
#pragma once
#include<iostream>
#include<assert.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 = 1900, int month = 1, int day = 1);
void Print();
int GetMonthDay(int year, int month)
{
assert(month > 0 && month < 13);
int monthDayArray[13] = { -1, 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 monthDayArray[month];
}
}
bool CheckDate()
{
if (_month < 1 || _month > 12)
return false;
if (_day < 1 || _day > GetMonthDay(_year, _month))
return false;
return true;
}
bool operator<(const Date& d);
bool operator<=(const Date& d);
bool operator>(const Date& d);
bool operator>=(const Date& d);
bool operator==(const Date& d);
bool operator!=(const Date& d);
// d1 += 天数
Date& operator+=(int day);
Date operator+(int day);
// d1 -= 天数
Date& operator-=(int day);
Date operator-(int day);
// d1 - d2
int operator-(const Date& d);
// ++d1 -> d1.operator++()
Date& operator++();
// d1++ -> d1.operator++(0)
// 为了区分,构成重载,给后置++,强行增加了一个int形参
// 这里不需要写形参名,因为接收值是多少不重要,也不需要用
// 这个参数仅仅是为了跟前置++构成重载区分
Date operator++(int);
// 前置
Date& operator--();
// 后置
Date operator--(int);
// d1.operator<<(cout);
/*void operator<<(ostream& out)
{
out << _year << "/" << _month << "/" << _day << '\n';
}*/
private:
int _year;
int _month;
int _day;
};
ostream& operator<<(ostream& out, const Date& d);
istream& operator>>(istream& in, Date& d);#define _CRT_SECURE_NO_WARNINGS 1
#include"Date.h"
Date::Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
if (!CheckDate())
{
cout << "非法日期:>" << *this;
}
}
void Date::Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
// d1 += 100
//Date& Date::operator+=(int day)
//{
// _day += day;
// while (_day > GetMonthDay(_year, _month))
// {
// _day -= GetMonthDay(_year, _month);
// ++_month;
// if (_month == 13)
// {
// ++_year;
// _month = 1;
// }
// }
//
// return *this;
//}
//
//// d1 + 100
//Date Date::operator+(int day)
//{
// Date tmp(*this);
//
// tmp._day += day;
// while (tmp._day > GetMonthDay(tmp._year, tmp._month))
// {
// tmp._day -= GetMonthDay(tmp._year, tmp._month);
// ++tmp._month;
// if (tmp._month == 13)
// {
// ++tmp._year;
// tmp._month = 1;
// }
// }
//
// return tmp;
//}
// d1 += 100
// d1 += -100
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;
}
// d1 + 100
Date Date::operator+(int day)
{
Date tmp(*this);
tmp += day;
return tmp;
}
// d1 += 100
//Date& Date::operator+=(int day)
//{
// *this = *this + day;
// return *this;
//}
//
//// d1 + 100
//Date Date::operator+(int day)
//{
// Date tmp(*this);
//
// tmp._day += day;
// while (tmp._day > GetMonthDay(tmp._year, tmp._month))
// {
// tmp._day -= GetMonthDay(tmp._year, tmp._month);
// ++tmp._month;
// if (tmp._month == 13)
// {
// ++tmp._year;
// tmp._month = 1;
// }
// }
//
// return tmp;
//}
// d1 -= 100 20:05
// d1 -= -100
Date& Date::operator-=(int day)
{
if (day < 0)
{
return *this += -day;
}
_day -= day;
while (_day <= 0)
{
--_month;
if (_month == 0)
{
--_year;
_month = 12;
}
_day += GetMonthDay(_year, _month);
}
return *this;
}
// d1 - 100
Date Date::operator-(int day)
{
Date tmp = *this;
tmp -= day;
return tmp;
}
// ++d1 -> d1.operator++();
Date& Date::operator++()
{
*this += 1;
return *this;
}
// d1++ -> d1.operator++(0);
Date Date::operator++(int)
{
Date tmp(*this);
*this += 1;
return tmp;
}
Date& Date::operator--()
{
*this -= 1;
return *this;
}
Date Date::operator--(int)
{
Date tmp = *this;
*this -= 1;
return tmp;
}
bool Date::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)
return _day < d._day;
}
return false;
}
// d1 <= d2
bool Date::operator<=(const Date& d)
{
return *this < d || *this == d;
}
bool Date::operator>(const Date& d)
{
return !(*this <= d);
}
bool Date::operator>=(const Date& d)
{
return !(*this < d);
}
bool Date::operator==(const Date& d)
{
return _year == d._year
&& _month == d._month
&& _day == d._day;
}
bool Date::operator!=(const Date& d)
{
return !(*this == d);
}
// d1 - d2 -> 9:12
int Date::operator-(const Date& d)
{
Date max = *this;
Date min = d;
int flag = 1;
if (*this < d)
{
min = *this;
max = d;
flag = -1;
}
int day = 0;
while (min != max)
{
++min;
++day;
}
return day * flag;
}
ostream& operator<<(ostream& out, const Date& d)
{
out << d._year << "/" << d._month << "/" << d._day << '\n';
return out;
}
istream& operator>>(istream& in, Date& d)
{
while (1)
{
cout << "请依次输入年月日:>";
in >> d._year >> d._month >> d._day;
if (d.CheckDate())
{
break;
}
else
{
cout << "输入日期非法,请重新输入" << endl;
}
}
return in;
}#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
//class Stack
//{
//public:
// Stack(int n)
// {}
//};
//
//class Myqueue
//{
//public:
// // 初始化列表,后面讲
// Myqueue()
// :_pushst(4)
// ,_popst(4)
// {}
//private:
// Stack _pushst;
// Stack _popst;
//};
//
//int main()
//{
// Myqueue q;
//
// return 0;
//}
//class Date
//{
//public:
// Date(int year = 1, int month = 1, int day = 1)
// {
// _year = year;
// _month = month;
// _day = day;
// }
//
// // Date d4(d3);
// //Date(const Date& d)
// //{
// // _year = d._year;
// // _month = d._month;
// // _day = d._day;
// //}
//
// void Print()
// {
// cout << _year << "-" << _month << "-" << _day << endl;
// }
//private:
// int _year;
// int _month;
// int _day;
//};
//
//// 自定义类型,传值传参要调用拷贝构造
//// void Func(const Date& d)
//void Func(Date d)
//{}
//
//typedef int STDataType;
//class Stack
//{
//public:
// Stack(int n = 4)
// {
// _a = (STDataType*)malloc(sizeof(STDataType) * n);
// if (nullptr == _a)
// {
// perror("malloc申请空间失败");
// return;
// }
// _capacity = n;
// _top = 0;
// }
//
// // Stack st2(st1);
// /*Stack(const Stack& s)
// {
// _a = s._a;
// _capacity = s._capacity;
// _top = s._top;
// }*/
//
// Stack(const Stack& s)
// {
// _a = (STDataType*)malloc(sizeof(STDataType) * s._capacity);
// if (_a == NULL)
// {
// perror("realloc fail");
// return;
// }
//
// memcpy(_a, s._a, s._top * sizeof(STDataType));
//
// _capacity = s._capacity;
// _top = s._top;
// }
//
// void Push(STDataType x)
// {
// if (_top == _capacity)
// {
// int newcapacity = _capacity * 2;
// STDataType* tmp = (STDataType*)realloc(_a, newcapacity *
// sizeof(STDataType));
// if (tmp == NULL)
// {
// perror("realloc fail");
// return;
// }
// _a = tmp;
// _capacity = newcapacity;
// }
// _a[_top++] = x;
// }
//
// ~Stack()
// {
// cout << "~Stack()" << endl;
// free(_a);
// _a = nullptr;
// _top = _capacity = 0;
// }
//private:
// STDataType* _a;
// size_t _capacity;
// size_t _top;
//};
//
//class MyQueue
//{
//private:
// Stack _pushst;
// Stack _popst;
//};
//int main()
//{
// Date d1(2025, 8, 1);
// // 拷贝构造
// Date d2(d1);
//
// const Date d3(2025, 8, 1);
// Date d4(d3);
//
// Func(d1);
//
// ////////////////////////////////////
// Stack st1;
// st1.Push(1);
// st1.Push(2);
// st1.Push(3);
//
// Stack st2(st1);
//
// MyQueue q1;
// MyQueue q2(q1);
//
// return 0;
//}
//int& func2()
//{
// int x = 1;
// return x;
//}
//
//Stack& Func3()
//{
// Stack st;
// return st;
//}
//
//// 10:30
//int main()
//{
// int ret1 = func2();
// cout << ret1 << endl;
//
// Stack ret2 = Func3();
// // Stack ret2(Func3());
//
// Stack st3;
// // 以下都是调用拷贝构造
// Stack st4(st3);
// Stack st5 = st3;
//
// return 0;
//}
//////////////////////////////////////////////////////////////////////////////////
// 运算符重载
//class Date
//{
//public:
// Date(int year = 1, int month = 1, int day = 1)
// {
// _year = year;
// _month = month;
// _day = day;
// }
//
// void Print()
// {
// cout << _year << "-" << _month << "-" << _day << endl;
// }
//
// int GetYear()
// {
// return _year;
// }
//
//private:
// int _year;
// int _month;
// int _day;
//};
//
//bool operator==(const Date& x1, const Date& x2)
//{
// return x1._year == x2._year
// && x1._month == x2._month
// && x1._day == x2._day;
//}
//
//int operator-(const Date& x1, const Date& x2)
//{
// return 0;
//}
//
//int main()
//{
// int i = 0, j = 1;
// Date d1(2025, 8, 1);
// Date d2(2025, 10, 1);
// bool ret = i == j;
// cout << (d1 == d2) << endl;
// operator==(d1, d2);
//
// d1 - d2;
// operator-(d1, d2);
//
// return 0;
//}
//class Date
//{
//public:
// Date(int year = 1, int month = 1, int day = 1)
// {
// _year = year;
// _month = month;
// _day = day;
// }
//
// void Print()
// {
// cout << _year << "-" << _month << "-" << _day << endl;
// }
//
// bool operator==(const Date& d)
// {
// return _year == d._year
// && _month == d._month
// && _day == d._day;
// }
//
//private:
// int _year;
// int _month;
// int _day;
//};
//
//int main()
//{
//
// Date d1(2025, 8, 1);
// Date d2(2025, 10, 1);
//
// cout << (d1 == d2) << endl;
// d1.operator==(d2);
//
// return 0;
//}
//void func1()
//{
// cout << "void func()" << endl;
//}
//
//class A
//{
//public:
// void func2()
// {
// cout << "A::func()" << endl;
// }
//};
//int main()
//{
// // 普通函数指针
// void(*pf1)() = func1;
// (*pf1)();
//
// // A类型成员函数的指针
// void(A::*pf2)() = &A::func2;
// A aa;
// (aa.*pf2)();
//
// return 0;
//}
// Date operator+(const Date& d, int x);
//int main()
//{
//
//
// return 0;
//}
//////////////////////////////////////////////////////////////////////
// 赋值运算符重载
//class Date
//{
//public:
// Date(int year = 1, int month = 1, int day = 1)
// {
// _year = year;
// _month = month;
// _day = day;
// }
//
// // Date d4(d3);
// Date(const Date& d)
// {
// _year = d._year;
// _month = d._month;
// _day = d._day;
// }
//
// // 11:40
// // d1 = d3 = d5
// // d1 = d1
// /*Date& operator=(const Date& d)
// {
// if (this != &d)
// {
// _year = d._year;
// _month = d._month;
// _day = d._day;
// }
//
// return *this;
// }*/
//
// void Print()
// {
// cout << _year << "-" << _month << "-" << _day << endl;
// }
//private:
// int _year;
// int _month;
// int _day;
//};
//
//int main()
//{
// Date d1(2025, 8, 1);
// Date d2(d1);
// // 一定注意,这个是拷贝构造
// Date d4 = d1;
//
// Date d3(2025, 10, 1);
// d1 = d3;
// Date d5(2025, 9, 1);
//
// d1 = d3 = d5;
//
// d1 = d1;
//
// return 0;
//}
///////////////////////////////////////////////////////
//#include"Date.h"
//
//int main()
//{
// /*Date d1(2025, 8, 1);
// Date d2 = d1 += 100;
// d1.Print();
// d2.Print();
//
// Date d3(2025, 8, 1);
// Date d4 = d3 + 100;
// d3.Print();
// d4.Print();*/
//
// Date d1(2025, 8, 1);
// Date ret1 = d1++;
// // Date ret1 = d1.operator++(10); // 显示调用,实参只要是整形就可以
//
// ret1.Print();
// d1.Print();
//
// Date d2(2025, 8, 1);
// Date ret2 = ++d2;
// //Date ret2 = d2.operator++();
// ret2.Print();
// d2.Print();
//
// return 0;
//}
#include"Date.h"
//Date operator+(Date d, int day)
//int operator-(Date d1, Date d2);
//int main()
//{
// Date d1(2025, 8, 1);
// Date d2(d1); // 拷贝构造
//
// Date d3(2025, 8, 11);
// d1 = d3; // 赋值拷贝 重载
//
// Date d4 = d1; // 拷贝构造
// Date d5(d1 + 100);
//
// //Date d6 = operator+(d1, 100);
// //Date d6 = d1.operator+(100);
// Date d7 = d1 + 100;
//
// d1.Print();
// d2.Print();
//
// return 0;
//}
void TestDate1()
{
Date d1(2025, 9, 8);
d1 -= 50;
d1.Print();
Date d2 = d1 - 50;
d2.Print();
Date d3(2025, 9, 8);
d3 -= 2000;
d3.Print();
Date d4(2025, 9, 8);
d4 -= -50;
d4.Print();
}
void TestDate2()
{
Date d1(2025, 9, 8);
//Date d2 = d1.operator--();
Date d2 = --d1; // d1.operator--();
d1.Print();
d2.Print();
//Date d3 = d1.operator--(1);
Date d3 = d1--; // d1.operator--(1);
d1.Print();
d3.Print();
Date d4(2025, 9, 8);
Date d5(2025, 10, 1);
cout << d4 - d5 << endl;
Date d6(2025, 12, 1);
cout << d4 - d6 << endl;
Date d7(2029, 7, 1);
cout << d4 - d7 << endl;
}
void TestDate3()
{
Date d1(2025, 9, 8);
Date d2(2025, 9, 90);
//operator<<(cout, d1);
cout << d1 << d2;
// 虽然可以跑,但是不符合可读性
//d1.operator<<(cout);
//d1 << cout;
cin >> d1 >> d2;
cout << d1 << d2;
}
int main()
{
TestDate3();
//int i = 1;
//double d = 1.1;
//cout << i; // cout.operator<<(i)
//cout << d; // cout.operator<<(d)
return 0;
}#pragma once
#include<iostream>
#include<assert.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 = 1900, int month = 1, int day = 1);
void Print() const;
int GetMonthDay(int year, int month) const
{
assert(month > 0 && month < 13);
int monthDayArray[13] = { -1, 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 monthDayArray[month];
}
}
bool CheckDate() const
{
if (_month < 1 || _month > 12)
return false;
if (_day < 1 || _day > GetMonthDay(_year, _month))
return false;
return true;
}
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;
// d1 += 天数
Date& operator+=(int day);
Date operator+(int day) const;
// d1 -= 天数
Date& operator-=(int day);
Date operator-(int day) const;
// d1 - d2
int operator-(const Date& d) const;
// ++d1 -> d1.operator++()
Date& operator++();
// d1++ -> d1.operator++(0)
// 为了区分,构成重载,给后置++,强行增加了一个int形参
// 这里不需要写形参名,因为接收值是多少不重要,也不需要用
// 这个参数仅仅是为了跟前置++构成重载区分
Date operator++(int);
// 前置
Date& operator--();
// 后置
Date operator--(int);
// d1.operator<<(cout);
/*void operator<<(ostream& out)
{
out << _year << "/" << _month << "/" << _day << '\n';
}*/
Date* operator&()
{
//return this;
return (Date*)0x00ff1204;
}
const Date* operator&() const
{
//return this;
return nullptr;
}
private:
int _year;
int _month;
int _day;
};
ostream& operator<<(ostream& out, const Date& d);
istream& operator>>(istream& in, Date& d);#define _CRT_SECURE_NO_WARNINGS 1
#include"Date.h"
Date::Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
if (!CheckDate())
{
cout << "非法日期:>" << *this;
}
}
void Date::Print() const
{
cout << _year << "-" << _month << "-" << _day << endl;
}
// d1 += 100
//Date& Date::operator+=(int day)
//{
// _day += day;
// while (_day > GetMonthDay(_year, _month))
// {
// _day -= GetMonthDay(_year, _month);
// ++_month;
// if (_month == 13)
// {
// ++_year;
// _month = 1;
// }
// }
//
// return *this;
//}
//
//// d1 + 100
//Date Date::operator+(int day)
//{
// Date tmp(*this);
//
// tmp._day += day;
// while (tmp._day > GetMonthDay(tmp._year, tmp._month))
// {
// tmp._day -= GetMonthDay(tmp._year, tmp._month);
// ++tmp._month;
// if (tmp._month == 13)
// {
// ++tmp._year;
// tmp._month = 1;
// }
// }
//
// return tmp;
//}
// d1 += 100
// d1 += -100
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;
}
// d1 + 100
Date Date::operator+(int day) const
{
Date tmp(*this);
tmp += day;
return tmp;
}
// d1 += 100
//Date& Date::operator+=(int day)
//{
// *this = *this + day;
// return *this;
//}
//
//// d1 + 100
//Date Date::operator+(int day)
//{
// Date tmp(*this);
//
// tmp._day += day;
// while (tmp._day > GetMonthDay(tmp._year, tmp._month))
// {
// tmp._day -= GetMonthDay(tmp._year, tmp._month);
// ++tmp._month;
// if (tmp._month == 13)
// {
// ++tmp._year;
// tmp._month = 1;
// }
// }
//
// return tmp;
//}
// d1 -= 100 20:05
// d1 -= -100
Date& Date::operator-=(int day)
{
if (day < 0)
{
return *this += -day;
}
_day -= day;
while (_day <= 0)
{
--_month;
if (_month == 0)
{
--_year;
_month = 12;
}
_day += GetMonthDay(_year, _month);
}
return *this;
}
// d1 - 100
Date Date::operator-(int day) const
{
Date tmp = *this;
tmp -= day;
return tmp;
}
// ++d1 -> d1.operator++();
Date& Date::operator++()
{
*this += 1;
return *this;
}
// d1++ -> d1.operator++(0);
Date Date::operator++(int)
{
Date tmp(*this);
*this += 1;
return tmp;
}
Date& Date::operator--()
{
*this -= 1;
return *this;
}
Date Date::operator--(int)
{
Date tmp = *this;
*this -= 1;
return tmp;
}
bool Date::operator<(const Date& d) const
{
if (_year < d._year)
{
return true;
}
else if (_year == d._year)
{
if (_month < d._month)
return true;
else if (_month == d._month)
return _day < d._day;
}
return false;
}
// d1 <= d2
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);
}
bool Date::operator==(const Date& d) const
{
return _year == d._year
&& _month == d._month
&& _day == d._day;
}
bool Date::operator!=(const Date& d) const
{
return !(*this == d);
}
// d1 - d2 -> 9:12
int Date::operator-(const Date& d) const
{
Date max = *this;
Date min = d;
int flag = 1;
if (*this < d)
{
min = *this;
max = d;
flag = -1;
}
int day = 0;
while (min != max)
{
++min;
++day;
}
return day * flag;
}
ostream& operator<<(ostream& out, const Date& d)
{
out << d._year << "/" << d._month << "/" << d._day << '\n';
return out;
}
istream& operator>>(istream& in, Date& d)
{
while (1)
{
cout << "请依次输入年月日:>";
in >> d._year >> d._month >> d._day;
if (d.CheckDate())
{
break;
}
else
{
cout << "输入日期非法,请重新输入" << endl;
}
}
return in;
}#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
//class Stack
//{
//public:
// Stack(int n)
// {}
//};
//
//class Myqueue
//{
//public:
// // 初始化列表,后面讲
// Myqueue()
// :_pushst(4)
// ,_popst(4)
// {}
//private:
// Stack _pushst;
// Stack _popst;
//};
//
//int main()
//{
// Myqueue q;
//
// return 0;
//}
//class Date
//{
//public:
// Date(int year = 1, int month = 1, int day = 1)
// {
// _year = year;
// _month = month;
// _day = day;
// }
//
// // Date d4(d3);
// //Date(const Date& d)
// //{
// // _year = d._year;
// // _month = d._month;
// // _day = d._day;
// //}
//
// void Print()
// {
// cout << _year << "-" << _month << "-" << _day << endl;
// }
//private:
// int _year;
// int _month;
// int _day;
//};
//
//// 自定义类型,传值传参要调用拷贝构造
//// void Func(const Date& d)
//void Func(Date d)
//{}
//
//typedef int STDataType;
//class Stack
//{
//public:
// Stack(int n = 4)
// {
// _a = (STDataType*)malloc(sizeof(STDataType) * n);
// if (nullptr == _a)
// {
// perror("malloc申请空间失败");
// return;
// }
// _capacity = n;
// _top = 0;
// }
//
// // Stack st2(st1);
// /*Stack(const Stack& s)
// {
// _a = s._a;
// _capacity = s._capacity;
// _top = s._top;
// }*/
//
// Stack(const Stack& s)
// {
// _a = (STDataType*)malloc(sizeof(STDataType) * s._capacity);
// if (_a == NULL)
// {
// perror("realloc fail");
// return;
// }
//
// memcpy(_a, s._a, s._top * sizeof(STDataType));
//
// _capacity = s._capacity;
// _top = s._top;
// }
//
// void Push(STDataType x)
// {
// if (_top == _capacity)
// {
// int newcapacity = _capacity * 2;
// STDataType* tmp = (STDataType*)realloc(_a, newcapacity *
// sizeof(STDataType));
// if (tmp == NULL)
// {
// perror("realloc fail");
// return;
// }
// _a = tmp;
// _capacity = newcapacity;
// }
// _a[_top++] = x;
// }
//
// ~Stack()
// {
// cout << "~Stack()" << endl;
// free(_a);
// _a = nullptr;
// _top = _capacity = 0;
// }
//private:
// STDataType* _a;
// size_t _capacity;
// size_t _top;
//};
//
//class MyQueue
//{
//private:
// Stack _pushst;
// Stack _popst;
//};
//int main()
//{
// Date d1(2025, 8, 1);
// // 拷贝构造
// Date d2(d1);
//
// const Date d3(2025, 8, 1);
// Date d4(d3);
//
// Func(d1);
//
// ////////////////////////////////////
// Stack st1;
// st1.Push(1);
// st1.Push(2);
// st1.Push(3);
//
// Stack st2(st1);
//
// MyQueue q1;
// MyQueue q2(q1);
//
// return 0;
//}
//int& func2()
//{
// int x = 1;
// return x;
//}
//
//Stack& Func3()
//{
// Stack st;
// return st;
//}
//
//// 10:30
//int main()
//{
// int ret1 = func2();
// cout << ret1 << endl;
//
// Stack ret2 = Func3();
// // Stack ret2(Func3());
//
// Stack st3;
// // 以下都是调用拷贝构造
// Stack st4(st3);
// Stack st5 = st3;
//
// return 0;
//}
//////////////////////////////////////////////////////////////////////////////////
// 运算符重载
//class Date
//{
//public:
// Date(int year = 1, int month = 1, int day = 1)
// {
// _year = year;
// _month = month;
// _day = day;
// }
//
// void Print()
// {
// cout << _year << "-" << _month << "-" << _day << endl;
// }
//
// int GetYear()
// {
// return _year;
// }
//
//private:
// int _year;
// int _month;
// int _day;
//};
//
//bool operator==(const Date& x1, const Date& x2)
//{
// return x1._year == x2._year
// && x1._month == x2._month
// && x1._day == x2._day;
//}
//
//int operator-(const Date& x1, const Date& x2)
//{
// return 0;
//}
//
//int main()
//{
// int i = 0, j = 1;
// Date d1(2025, 8, 1);
// Date d2(2025, 10, 1);
// bool ret = i == j;
// cout << (d1 == d2) << endl;
// operator==(d1, d2);
//
// d1 - d2;
// operator-(d1, d2);
//
// return 0;
//}
//class Date
//{
//public:
// Date(int year = 1, int month = 1, int day = 1)
// {
// _year = year;
// _month = month;
// _day = day;
// }
//
// void Print()
// {
// cout << _year << "-" << _month << "-" << _day << endl;
// }
//
// bool operator==(const Date& d)
// {
// return _year == d._year
// && _month == d._month
// && _day == d._day;
// }
//
//private:
// int _year;
// int _month;
// int _day;
//};
//
//int main()
//{
//
// Date d1(2025, 8, 1);
// Date d2(2025, 10, 1);
//
// cout << (d1 == d2) << endl;
// d1.operator==(d2);
//
// return 0;
//}
//void func1()
//{
// cout << "void func()" << endl;
//}
//
//class A
//{
//public:
// void func2()
// {
// cout << "A::func()" << endl;
// }
//};
//int main()
//{
// // 普通函数指针
// void(*pf1)() = func1;
// (*pf1)();
//
// // A类型成员函数的指针
// void(A::*pf2)() = &A::func2;
// A aa;
// (aa.*pf2)();
//
// return 0;
//}
// Date operator+(const Date& d, int x);
//int main()
//{
//
//
// return 0;
//}
//////////////////////////////////////////////////////////////////////
// 赋值运算符重载
//class Date
//{
//public:
// Date(int year = 1, int month = 1, int day = 1)
// {
// _year = year;
// _month = month;
// _day = day;
// }
//
// // Date d4(d3);
// Date(const Date& d)
// {
// _year = d._year;
// _month = d._month;
// _day = d._day;
// }
//
// // 11:40
// // d1 = d3 = d5
// // d1 = d1
// /*Date& operator=(const Date& d)
// {
// if (this != &d)
// {
// _year = d._year;
// _month = d._month;
// _day = d._day;
// }
//
// return *this;
// }*/
//
// void Print()
// {
// cout << _year << "-" << _month << "-" << _day << endl;
// }
//private:
// int _year;
// int _month;
// int _day;
//};
//
//int main()
//{
// Date d1(2025, 8, 1);
// Date d2(d1);
// // 一定注意,这个是拷贝构造
// Date d4 = d1;
//
// Date d3(2025, 10, 1);
// d1 = d3;
// Date d5(2025, 9, 1);
//
// d1 = d3 = d5;
//
// d1 = d1;
//
// return 0;
//}
///////////////////////////////////////////////////////
//#include"Date.h"
//
//int main()
//{
// /*Date d1(2025, 8, 1);
// Date d2 = d1 += 100;
// d1.Print();
// d2.Print();
//
// Date d3(2025, 8, 1);
// Date d4 = d3 + 100;
// d3.Print();
// d4.Print();*/
//
// Date d1(2025, 8, 1);
// Date ret1 = d1++;
// // Date ret1 = d1.operator++(10); // 显示调用,实参只要是整形就可以
//
// ret1.Print();
// d1.Print();
//
// Date d2(2025, 8, 1);
// Date ret2 = ++d2;
// //Date ret2 = d2.operator++();
// ret2.Print();
// d2.Print();
//
// return 0;
//}
#include"Date.h"
//Date operator+(Date d, int day)
//int operator-(Date d1, Date d2);
//int main()
//{
// Date d1(2025, 8, 1);
// Date d2(d1); // 拷贝构造
//
// Date d3(2025, 8, 11);
// d1 = d3; // 赋值拷贝 重载
//
// Date d4 = d1; // 拷贝构造
// Date d5(d1 + 100);
//
// //Date d6 = operator+(d1, 100);
// //Date d6 = d1.operator+(100);
// Date d7 = d1 + 100;
//
// d1.Print();
// d2.Print();
//
// return 0;
//}
void TestDate1()
{
Date d1(2025, 9, 8);
d1 -= 50;
d1.Print();
Date d2 = d1 - 50;
d2.Print();
Date d3(2025, 9, 8);
d3 -= 2000;
d3.Print();
Date d4(2025, 9, 8);
d4 -= -50;
d4.Print();
}
void TestDate2()
{
Date d1(2025, 9, 8);
//Date d2 = d1.operator--();
Date d2 = --d1; // d1.operator--();
d1.Print();
d2.Print();
//Date d3 = d1.operator--(1);
Date d3 = d1--; // d1.operator--(1);
d1.Print();
d3.Print();
Date d4(2025, 9, 8);
Date d5(2025, 10, 1);
cout << d4 - d5 << endl;
Date d6(2025, 12, 1);
cout << d4 - d6 << endl;
Date d7(2029, 7, 1);
cout << d4 - d7 << endl;
}
void TestDate3()
{
Date d1(2025, 9, 8);
Date d2(2025, 9, 90);
//operator<<(cout, d1);
cout << d1 << d2;
// 虽然可以跑,但是不符合可读性
//d1.operator<<(cout);
//d1 << cout;
cin >> d1 >> d2;
cout << d1 << d2;
}
void TestDate4()
{
const Date d1(2025, 9, 8);
d1.Print();
Date d3 = d1 + 100;
Date d2(2025, 9, 8);
d2.Print();
d2 += 10;
bool ret = d1 > d2;
Date* p1 = &d2;
const Date* p2 = &d1;
cout << p1 << " " << p2 << endl;
}
//int main()
//{
// TestDate3();
//
// //int i = 1;
// //double d = 1.1;
// //cout << i; // cout.operator<<(i)
// //cout << d; // cout.operator<<(d)
//
// return 0;
//}
int main()
{
TestDate4();
return 0;
}