C++从入门到起飞之——const成员函数&Date类实现 全方位剖析!
秋风起,再归来~ 2024-07-29 13:05:03 阅读 99
🌈个人主页:秋风起,再归来~
🔥系列专栏:C++从入门到起飞
🔖克心守己,律己则安
代码链接:这篇文章代码的所有代码都在我的gitee仓库里面啦,需要的小伙伴点击自取哦~
目录
1、const成员函数
2、取地址运算符重载
3、日期类的实现
3.1Date.h
3.2Date.cpp
0、检查日期是否有效
1、获取某年某月的天数
2、全缺省的构造函数
3、拷贝构造函数
4、赋值运算符重载
5、析构函数
6、日期+=天数
7、日期+天数
8、日期-天数
9、日期-=天数
10、前置++
11、后置++
12、 后置--
13、 前置--
14、>运算符重载
15、==运算符重载
16、 >=运算符重载
17、<运算符重载
18、<=运算符重载
19、!=运算符重载
20、日期-日期 返回天数
21、流插入函数重载
22、流提取函数重载
3.3Test.cpp
4.完结散花
1、const成员函数
• 将const修饰的成员函数称之为const成员函数,const修饰成员函数放到成员函数参数列表的后 ⾯。
• const实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进⾏修改。 const修饰Date类的Print成员函数,Print隐含的this指针由 Date* const this 变为 const Date* const this
<code>#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;
}
2、取地址运算符重载
取地址运算符重载分为普通取地址运算符重载和const取地址运算符重载。
class Date
{
public:
Date* operator&()
{
return this;
// return nullptr;
}
const Date* operator&()const
{
return this;
// return nullptr;
}
private:
int _year; // 年
int _month; // ⽉
int _day; // ⽇
};
⼀般这两个函数编译器⾃动 ⽣成的就可以够我们⽤了,不需要去显⽰实现。除⾮⼀些很特殊的场景,⽐如我们不想让别⼈取到当 前类对象的地址,就可以⾃⼰实现⼀份,胡乱返回⼀个地址。
class Date
{
public:
Date* operator&()
{
return (Date*)0x11223344;
// return nullptr;
}
const Date* operator&()const
{
return (Date*)0x11223344;
// return nullptr;
}
private:
int _year; // 年
int _month; // ⽉
int _day; // ⽇
};
int main()
{
Date d1, d2;
cout << &d1 <<endl<< &d2 << endl;
return 0;
}
俩个对象的地址都是胡乱返回的(真的损!)
3、日期类的实现
3.1Date.h
为了便于代码的可读性,我们在日期类中将我们目前需要的成员函数进行声明和定义分离!
下面我们先在日期类(Date.h)中声明了我们要完成的一些功能(成员函数)
<code>#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<assert.h>
using namespace std;
class Date
{
public:
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
// 0、检查日期是否有效
bool CheckDate();
// 1、获取某年某月的天数
int GetMonthDay(int year, int month);
// 2、全缺省的构造函数
Date(int year = 1900, int month = 1, int day = 1);
// 3、拷贝构造函数
Date(const Date& d);
// 4、赋值运算符重载
Date& operator=(const Date& d);
// 5、析构函数
~Date();
// 6、日期+=天数
Date& operator+=(int day);
// 7、日期+天数
Date operator+(int day)const;
// 8、日期-天数
Date operator-(int day)const;
// 9、日期-=天数
Date& operator-=(int day);
// 10、前置++
Date& operator++();
// 11、后置++
Date operator++(int);
// 12、后置--
Date operator--(int);
// 13、前置--
Date& operator--();
// 14、>运算符重载
bool operator>(const Date& d)const;
// 15、==运算符重载
bool operator==(const Date& d)const;
//16、 >=运算符重载
bool operator >= (const Date& d)const;
// 17、<运算符重载
bool operator < (const Date& d)const;
// 18、<=运算符重载
bool operator <= (const Date& d)const;
// 19、!=运算符重载
bool operator != (const Date& d)const;
// 20、日期-日期 返回天数
int operator-(const Date& d)const;
// 21、流插入函数重载
friend ostream& operator<<(ostream& out, const Date& d);
// 22、流提取函数重载
friend istream& operator>>(istream& in, Date& d);
private:
int _year;
int _month;
int _day;
};
3.2Date.cpp
好啦!接下来我们就在Date.cpp这个文件中定义我们要实现的全部成员函数!
0、检查日期是否有效
// 0、检查日期是否有效
bool Date::CheckDate()
{
if (_month < 1 || _month > 12
|| _day < 1 || _day > GetMonthDay(_year, _month))
{
return false;
}
else
{
return true;
}
}
1、获取某年某月的天数
// 1、获取某年某月的天数
// 因为会被多次调用,所以直接在类里面定义(默认是inline)
int GetMonthDay(int year, int month)
{
assert(month > 0 && month < 13);
static int monthDayArray[13] = { 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 monthDayArray[month];
}
}
因为会被多次调用,所以直接在类里面定义(默认是inline),这样我们就可以避免频繁的调用该函数建立栈帧,从而提高性能!
2、全缺省的构造函数
这里需要注意在声明中写了缺省值后,定义时不能再写缺省值!
// 2、全缺省的构造函数
Date::Date(int year , int month , int day )
{
_year = year;
_month = month;
_day = day;
if (!CheckDate())
{
cout << "非法日期:";
Print();
}
}
3、拷贝构造函数
// 3、拷贝构造函数
Date::Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
4、赋值运算符重载
// 4、赋值运算符重载
Date& Date::operator=(const Date& d)
{
if (this != &d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
return *this;
}
5、析构函数
Date类其实没有必要显示自定义析构函数!
// 5、析构函数
Date::~Date()
{
//cout << "~Date()" << endl;
}
6、日期+=天数
// 6、日期+=天数
Date& Date::operator+=(int day)
{
_day += day;
while (_day > GetMonthDay(_year,_month))
{
_day -= GetMonthDay(_year, _month);
_month++;
if (_month > 12)
{
_month = 1;
_year++;
}
}
return *this;
}
7、日期+天数
这里复用了+=的代码!
// 7、日期+天数
Date Date::operator+(int day) const
{
Date tmp = *this;
tmp += day;
return tmp;
}
8、日期-天数
// 8、日期-天数
Date Date::operator-(int day)const
{
Date tmp = *this;
tmp -= day;
return tmp;
}
9、日期-=天数
// 9、日期-=天数
Date& Date::operator-=(int day)
{
_day -= day;
while (_day < 0)
{
_month--;
_day += GetMonthDay(_year, _month);
if (_month == 0)
{
_month = 12;
_year--;
}
}
return *this;
}
10、前置++
// 10、前置++
Date& Date::operator++()
{
*this += 1;
return *this;
}
11、后置++
为了区别前置++和后置++,C++规定后置++多一个参数(int)以示区分!
// 11、后置++
Date Date::operator++(int)
{
Date tmp = *this;
*this += 1;
return tmp;
}
12、 后置--
// 12、后置--
Date Date::operator--(int)
{
Date tmp = *this;
*this -= 1;
return tmp;
}
13、 前置--
// 13、前置--
Date& Date::operator--()
{
*this -= 1;
return *this;
}
14、>运算符重载
// 14、>运算符重载
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;
}
15、==运算符重载
// 15、==运算符重载
bool Date::operator==(const Date& d)const
{
return _year == d._year
&& _month == d._month
&& _day == d._day;
}
16、 >=运算符重载
//16、 >=运算符重载
bool Date::operator >= (const Date& d)const
{
return *this > d || *this == d;
}
17、<运算符重载
// 17、<运算符重载
bool Date::operator < (const Date& d)const
{
return !(*this >= d);
}
18、<=运算符重载
// 18、<=运算符重载
bool Date::operator <= (const Date& d)const
{
return *this < d || *this == d;
}
19、!=运算符重载
// 19、!=运算符重载
bool Date::operator != (const Date& d)const
{
return !(*this == d);
}
20、日期-日期 返回天数
// 20、日期-日期 返回天数
int Date::operator-(const Date& d)const
{
Date max = *this;
Date min = d;
int flag = 1;
if (*this < d)
{
max = d;
min = *this;
flag = -1;
}
int n = 0;
while (min != max)
{
++min;
++n;
}
return n * flag;
}
21、流插入函数重载
// 21、流插入函数重载
ostream& operator<<(ostream& out,const Date& d)
{
cout << d._year << "年" << d._month << "月" << d._day << "日" << endl;
return out;
}
为什么这个函数不定义为成员函数,反而要在全局中定义呢?
其实我们也是可以在类里面声明定义的?不过这里头会出现一些小问题!
// 21、流插入函数重载
ostream& operator<<(ostream& out)
{
cout << _year << "年" << _month << "月" << _day << "日" << endl;
return out;
}
// 22、流提取函数重载
istream& operator>>(istream& in)
{
while (1)
{
cout << "请输入合法日期>" << endl;
cout << "年:";
cin >> _year;
cout << "月:";
cin >> _month;
cout << "日:";
cin >> _day;
cout << "-----------------" << endl;
if (!CheckDate())
{
cout << "输入非法日期:";
Print();
}
else
{
break;
}
}
return in;
}
当我们定义到类里面时,参数列表中的第一个参数默认是隐含的(Date* const this) ,这恰好与我们在全局外定义的相反,从而导致如果我们在使用该函数时按照我们的习惯去写的话,编译器会直接报错!
必须这样书写!
<code>Date d1, d2;
d1 >> cin;
d1 << cout;
我们可以看到这非常不符合我们的习惯!所以我们将他们定义到全局中,方便我们进行参数的调整。但我们又面临如何访问到类内部私有成员的问题,有以下几种方法:
1、将私有成员直接放开为public(最挫的方法)
2、提供get方法得到私有成员
3、使用友元函数
4、重载为成员函数(这里因参数问题就不可用了)
我这里使用了友元函数的方法(到后面我会具体讲解该函数的!)
22、流提取函数重载
// 22、流提取函数重载
istream& operator>>(istream& in, Date& d)
{
while (1)
{
cout << "请输入合法日期>" << endl;
cout << "年:";
cin >> d._year;
cout << "月:";
cin >> d._month;
cout << "日:";
cin >> d._day;
cout << "-----------------"<<endl;
if (!d.CheckDate())
{
cout << "输入非法日期:";
d.Print();
}
else
{
break;
}
}
return in;
}
3.3Test.cpp
下面代码是我在实现日期类时的检测(仅供参考)
#include"Date.h"
void Test1()
{
Date d1(2024, 7, 21);
Date d2(2024, 7, 22);
Date d3 = d1;
d3.Print();
d3 = d2;
d3.Print();
Date d4=d3 + 3000;
d4.Print();
}
void Test2()
{
Date d1(2024, 7, 23);
/*d1 -= 100;
d1.Print();*/
/*++d1;
d1.Print();
Date ret=d1++;
ret.Print();
d1.Print();*/
}
void Test3()
{
Date d1(2024, 7, 21);
Date d2(2024, 7, 22);
bool ret = d1 >= d2;
cout << ret << endl;
int ret1 = d1 - d2;
cout << ret1 << endl;
}
void Test4()
{
Date d1(2050, 3, 21);
Date d2(2024, 7, 22);
/*bool ret = d1 >= d2;
cout << ret << endl;*/
int ret1 = d1 - d2;
cout << ret1 << endl;
}
void Test5()
{
Date d1, d2;
cin >> d1 >> d2;
cout << d1 << d2;
}
int main()
{
//Test1();
//Test2();
//Test3();
//Test4();
Test5();
return 0;
}
4.完结散花
好了,这期的分享到这里就结束了~
如果这篇博客对你有帮助的话,可以用你们的小手指点一个免费的赞并收藏起来哟~
如果期待博主下期内容的话,可以点点关注,避免找不到我了呢~
我们下期不见不散~~
上一篇: Java中正确判断BigDecimal是否为空的多种方法及其应用场景
本文标签
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。