2024年网络安全最全C++类和对象一站式总结【日期类的实现】附源码【收藏(2),2024年最新网络安全开发入门与实战

还有兄弟不知道网络安全面试可以提前刷题吗?费时一周整理的160+网络安全面试题,金九银十,做网络安全面试里的显眼包!

王岚嵚工程师面试题(附答案),只能帮兄弟们到这儿了!如果你能答对70%,找一个安全工作,问题不大。

对于有1-3年工作经验,想要跳槽的朋友来说,也是很好的温习资料!

【完整版领取方式在文末!!】

93道网络安全面试题

内容实在太多,不一一截图了

黑客学习资源推荐

最后给大家分享一份全套的网络安全学习资料,给那些想学习 网络安全的小伙伴们一点帮助!

对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。

1️⃣零基础入门
① 学习路线

对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。

image

② 路线对应学习视频

同时每个成长路线对应的板块都有配套的视频提供:

image-20231025112050764

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化资料的朋友,可以点击这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

int height;
int weight;

};


2、声明定义分开处理



class animal
{
//成员函数
void _sleep();
void _catch();
//成员变量
int age;
int height;
int weight;
};
//指定_catch函数和_sleep属于animal类域,定义声明分开时这样处理
void animal::_catch()
{
printf(“猎杀时刻\n”);
}
void animal::_sleep()
{
printf(“早睡早起\n”);
}


### 类的访问限定符


![在这里插入图片描述](https://img-blog.csdnimg.cn/3947017a2f304da2bc63c5287a64f1fa.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASVTojqvmiY7nibk=,size_20,color_FFFFFF,t_70,g_se,x_16)


1. public修饰的成员在类外可以直接被访问
2. protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)
3. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
4. class的默认访问权限为private,struct为public(因为struct要兼容C)
5. 访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别


### C++中struct和class的区别是什么?



> 
> C++需要兼容C语言,所以C++中struct可以当成结构体去使用。另外C++中struct还可以用来定义类。和class是定义类是一样的,区别是struct的成员默认访问方式是public,class是的成员默认访问方式是  
>  private。
> 
> 
> 


## 类的基本概念


### 面向对象的三大特性:封装、继承、多态



> 
> 封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互,封装本质上是一种管理
> 
> 
> 


### 类的作用域


类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员,需要使用 :: 作用域解析符指明成员属于哪个类域



//当类的成员函数声明和定义分开时,需要指定该函数在哪个类域中
class animal
{
//成员函数的声明
void func();
};

//指定该函数在animal类域中声明过
void animal::func()
{
//代码
}


### 类的实例化



> 
> 1、用类类型创建对象的过程,称为类的实例化  
>  2. 类只是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它  
>  3. 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量
> 
> 
> 


## 重点:this指针



class Date
{
public:
void showDate()
{
cout << _year << “-” << _month << “-” << _day<< endl;
}
//实际上的SetDate函数是这样的:
//void SetDate(Date *this, int year, int month, int day)
void SetDate(int year, int month, int day)
{
_year= year;
_month= month;
_day= day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1, d2;
//设置对象的成员变量值,由于类成员变量已经被私有化了
//,要想在外界访问只有通过成员函数访问,成员函数是公有的
d1.SetDate(2021, 10, 27);
d2.SetDate(2020, 3, 27);
//打印值
d1.showDate();
d2.showDate();
return 0;
}



> 
> 通过SetDate函数去初始化对象成员变量,其实编译器在处理的时候实际上会多添加一个参数这个参数是一个指针类型,他叫this,在传参的时候会将对象的地址传递给this,这样this就指向了这个对象,这样子就能通过this去修改该对象里面成员变量的值,既然是隐藏的,this可以加,但不推荐  
>  ![在这里插入图片描述](https://img-blog.csdnimg.cn/3c6038c5fde4446f9b29836e0297cf5b.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASVTojqvmiY7nibk=,size_20,color_FFFFFF,t_70,g_se,x_16)  
>  打印this的值和打印对象的地址是一样的,他们共属于一个东西  
>  ![在这里插入图片描述](https://img-blog.csdnimg.cn/f073f045b1f04056a3d9f354ef632c1a.png)
> 
> 
> 


### 总结及补充:


该类对象去调用该类成员函数时,通常会将对象的地址传递过去,而this就是指向这个对象的,通过this去修改对象的成员属性


补充:  
 1、this指针是隐含的,是编译器编译时加的,不能显示的在调用和函数定义中加  
 2、可以在成员函数中使用this  
 3、this一般是存在栈上的,不同的编译器不同,vs使用的是ecx寄存器存储传参的


这里将对象的地址d1存储到ecx寄存器中,通过使用vs2013反汇编观察到的现象  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/abb699a583b94aaaa59b5c5a127ff50a.png)


### 进一步加强对this的理解


以下程序会崩溃吗?



class A
{
public:
void PrintA()
{
cout<<_a<<endl;
}

void Show()
{
cout<<"Show()"<<endl;
}

private:
int _a;
};
int main()
{
A* p = nullptr;
p->PrintA(); //空指针解引用非法,程序崩溃
p->Show();//正常运行
}



> 
> p->PrintA();程序崩溃,因为对象本身是一个指针类型,但是却是空指针,在调用成员函数的时候,将空指针传递给this,this再去访问该对象的成员变量,就会有空指针解引用行为,程序会崩,p->Show();正常运行,因为并没有去访问该类对象的成员变量,并且成员函数的地址并不会存放到对象里面,所以是完全ok的
> 
> 
> 


## 类的6个默认成员函数


默认成员函数的概念:我们不写,编译器自动生成的成员函数就叫默认成员函数  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/9b1fd0b96c894c468e6ea56fafcfbb78.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASVTojqvmiY7nibk=,size_20,color_FFFFFF,t_70,g_se,x_16)


### 构造函数


构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,保证每个数据成员都有 一个合适的初始值,并且在对象的生命周期内只调用一次。构造函数是特殊的成员函数,构造函数的虽然名称叫构造,但是构造函数的主要任务并不是开空间创建对象,而是初始化对象。



class Date
{
public:
//带参数的构造函数
Date(int year, int month, int day);
//不带参数的构造函数
Date();
private:
int _year;
int _month;
int _day;
};
//类中声明,类外定义,指定是哪个类域
Date::Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
//
Date::Date()
{
}


#### 构造特征:


1. 函数名与类名相同。
2. 无返回值。
3. 对象实例化时编译器自动调用对应的构造函数。
4. 构造函数可以重载


注意:  
 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成,默认构造函数是不会去初始化对象的成员的



> 
> 如果使用编译器提供的默认构造函数,对象成员的值就会是随机值  
>  ![在这里插入图片描述](https://img-blog.csdnimg.cn/c54055964da44e4abbd961fb2c00c7cb.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASVTojqvmiY7nibk=,size_20,color_FFFFFF,t_70,g_se,x_16)
> 
> 
> 


显示定义构造函数



class Date
{
//不指定参数,显示定义构造函数,编译器不再提供
Date()
{
//代码
}
//一般推荐带参数的构造函数,并提供缺省参数
Date(int year = 2021, int month = 10, int day = 28)
{
//代码
}
};


无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。


注意:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认成员函数


### 析构函数


析构函数不是完成对象的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成类对象的一些资源清理工作



class Date
{
Date(int year = 2021, int month = 10, int day = 28)
{
//代码
}
//无须提供参数不带返回值,自动被调用完成对象的资源清理
~Date()
{
//代码
}
};


#### 析构函数特征



析构函数是特殊的成员函数。

1. 析构函数名是在类名前加上字符 ~。
2. 无参数无返回值。
3. 一个类有且只有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。
4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。
5. 编译器默认生成的析构函数,对于内置类型成员不会处理,而对于自定义类型成员会处理
6. 同样的析构函数跟构造函数也是类似,如果我们不写编译器会自动提供默认的析构函数,如果我们写编译器就不再提供默认的析构函数


**析构函数的析构顺序**  
 先进后出,后进先出,符合栈的特性



class Date
{
public:
Date()
{
cout << this << “对象创建” << endl;

}
~Date() 
{
	cout << this << "对象析构 " << endl;
}

private:
int _year; // 年
int _month; // 月
int _day; // 日
};

int main()
{
Date d1;
Date d2;
Date d3;
return 0;
}


观察到的现象是先创建的对象后析构,后创建的对象先析构  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/cb2e033024cb4bf4b6b8e3b05c14b10c.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASVTojqvmiY7nibk=,size_20,color_FFFFFF,t_70,g_se,x_16)


## 拷贝构造函数



> 
> 拷贝构造函数也属于类的六个默认构造函数:只有单个形参,该形参是一个类型对象的引用,一般常用const修饰(加const的目的:只做拷贝,不做修改),用已经存在的对象拷贝构造出一个新的对象,完成拷贝构造对象的初始化
> 
> 
> 


### 特征:


1. 拷贝构造函数是构造函数的一个重载形式。
2. 拷贝构造函数的参数只有一个且必须使用引用传参,使用传值方式会引发无穷递归调用
3. 拷贝构造函数也是属于默认成员函数,我们不写编译器自动生成拷贝构造,这个拷贝构造会对内置类型完成浅拷贝,或者值拷贝


**再学习浅拷贝之前,我们先学习拷贝构造函数在哪些场景会存在问题**  
 1、如果是值传递的方式调用拷贝构造函数会存在一定的隐患,会陷入无限死循环,  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/4b361d068ccf4d988feaaa4379e850cc.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASVTojqvmiY7nibk=,size_20,color_FFFFFF,t_70,g_se,x_16)


正确写法,必须传递引用,使用引用的方式是为了给给对象取别名,调用拷贝构造出一个新的对象,传递引用并不会存在死循环



class Date
{
public:
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
//自定义拷贝构造函数,引用传递
Date(Date& d1)
{
_year = d1._year;
_month = d1._month;
_day = d1._day;
}
void Dateshow()
{
cout<< _year << " " << _month << " " << _day << endl;
}
int _year; // 年
int _month; // 月
int _day; // 日
};

int main()
{
Date d1(2021 ,10 ,30);
//调用拷贝构造函数完成对d2对象的初始化
Date d2(d1);

d1.Dateshow();
d2.Dateshow();
return 0;

}


补充:针对于自定义类型推荐传递引用,值传递会调用拷贝构造函数,也是会存在一定的消耗的


### 浅拷贝带来的隐患举例


如果是用一个类创建出来两个对象,这两个对象的成员中都含有一个指针,并且它们都是指向同一块空间的,当这两个对象被销毁时编译器自动调用析构函数,这样子一来同一块空间就会被释放两次,解决浅拷贝的办法就是深拷贝,后序再来讲解


总结:  
 浅拷贝的问题,调用析构函数时,同一块空间被释放两次


## 运算符重载


C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。


函数名字为:关键字operator后面接需要重载的运算符符号。  
 函数原型:返回值类型 operator操作符(参数列表


**注意:**


* 1、不能通过连接其他符号来创建新的操作符:比如operator@ 2、重载操作符必须有一个类类型或者枚举类型的操作数  
 3、用于内置类型的操作符,其含义不能改变,例如:内置的整型+,不 能改变其含义  
 4、作为类成员的重载函数时,其形参看起来比操作数数目少1成员函数的操作符有一个默认的形参this,限定为第一个形参  
 5、.\* 、::、sizeof 、?: 、. 注意以上5个运算符不能重载。这个经常在笔试选择题中出现



> 
> 内置类型本身是支持运算符的,而自定义类型默认不支持,而C++可以用运算符重载来让类对象支持某个运算符
> 
> 
> 


这里举例两种运算符重载方式,目的是为了让读者知道其中的意义在哪,先看在类中重载运算符



class Date
{
public:
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
//等号运算符重载
bool operator==(Date d2)
{
return _year == d2._year
&& _month == d2._month
&& _day == d2._day;
}
private:
int _year; // 年
int _month; // 月
int _day; // 日
};

int main()
{
Date d1(2021, 10, 29);
Date d2(2021, 10, 29);
Date d3(2021, 10, 30);
//比较两个对象的大小
bool ret = d1.operator==(d2);//true
return 0;
}



> 
> operator==(Date d2),C++的一个运算符重载语法,operator==表示的是函数名,后面的括号里面带的是函数的参数,是一个类类型的形参,该函数的功能是将两个对象进行比较,将比较的结果值返回,当然这里是布尔类型,这里同样也是值传递
> 
> 
> 


![在这里插入图片描述](https://img-blog.csdnimg.cn/336ba69ebdcf470483e6f7ea52efad7c.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASVTojqvmiY7nibk=,size_20,color_FFFFFF,t_70,g_se,x_16)


调用处会将d1的地址传递给this,那么this就指向这个对象d1,而对象d2是通过值拷贝的方式过去的,那么就可以对这两个对象的成员进行比较,最后将结果返回


再来看第二种方式,他的设计并不像第一种方式那么灵活,反而看起来很生硬



class Date
{
public:
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}

int _year; // 年
int _month; // 月
int _day; // 日

};

//类外重载运算符比较两个对象的大小
bool operator==(Date d1, Date d2)
{
return d1._year == d2._year
&& d1._month == d2._month
&& d1._day == d2._day;
}

int main()
{
Date d1(2021, 10, 29);
Date d2(2021, 10, 29);
Date d3(2021, 10, 30);
//bool ret = d1.operator==(d3);
bool ret = d1 == d2;//true
return 0;
}


对比这两种写法,当然在类外重载后使用起来会更简洁,但是就破坏了封装性,相比之下在类中重载代码管理起来也方便,并且还利于类的封装性,其实编译器在内部也会将d1 == d2 转换为d1.operator==(d3);,所以在实现上还是推荐第一种写法


![在这里插入图片描述](https://img-blog.csdnimg.cn/3a96ba45a5d14e1a81ecdf173b4de9d5.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASVTojqvmiY7nibk=,size_20,color_FFFFFF,t_70,g_se,x_16)


### 重载[ ]运算符



class Array
{
public:
//调用构造函数完成对象的初始化
Array()
{
_numsize = 10;
for (int i = 0; i < _numsize; i++)
{
_arr[i] = i ;
}
}
//获取_numsize
inline int& length()
{
return _numsize;
}
//重载[]运算符,返回数组索引下标的位置
inline int& operator[](int pos)
{
return _arr[pos];
}

private:
int _arr[100];
int _numsize;
};
int main()
{

Array arr;
//循环取出对象成员数组的值并打印
for (int i = 0; i < arr.length(); i++)
{
	cout << arr[i] << endl;
}

return 0;

}



> 
> 通过operator[](int pos) 重载运算符后对象arr无需再使用 . 去访问成员而是通过重载[ ]后直接对成员访问,更为便捷,当然函数体比较小,加上内联更合适
> 
> 
> 


### 拷贝复制运算符



> 
> 看下面这个例子,将一个对象d1赋值给另外一个对象,在这个时候编译器会自动调用我们重载过后的 operator=拷贝赋值运算符,将d1对象的值拷贝赋值到d2对象
> 
> 
> 



class Date
{
public:
//自定义拷贝构造函数
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
Date(Date& d)
{
cout << “调用了拷贝构造函数:Date(Date& d)” << endl;
}
//重载赋值运算符,使自定义类型也能像内置类型一样使用操作符
Date operator=(const Date& d1)
{
_year = d1._year;
_day = d1._day;
_month = d1._month;

	cout << "operator=()" << endl;
	//返回值带回去的时候会将this
	//这个对象拷贝构造出一个临时对象,最后将临时对象带回去
	return \*this;
}

private:
int _year;
int _month;
int _day;
};

int main()
{
Date d1(2021, 10, 30);
Date d2 = d1;

return 0;

}


需要注意的是这里会产生一个临时对象,因为重载的operator=它的返回值是一个对象,并不是引用,值返回会多调用一次拷贝构造函数,从打印的结果可以看出  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/0e36f35e48ff44e08286e4b0de842f43.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASVTojqvmiY7nibk=,size_20,color_FFFFFF,t_70,g_se,x_16)  
 可以再改善一下,引用加上防止多调用一次拷贝构造函数



Date& operator=(const Date& d1)
{
	//如果对象不是自己本身就对他处理,否则不需要,自己拷贝自己没意思
	if(this != &d1)
	{
		_year = d1._year;
		_day = d1._day;
		_month = d1._month;
	}

	cout << "operator=()" << endl;
	//返回值带回去的时候会将this
	//这个对象拷贝构造出一个临时对象,最后将临时对象带回去
	return \*this;
}

补充:  
 赋值运算符也是一个默认成员函数,我们不写编译器会默认生成一个,编译器默认生成赋值运算符跟拷贝构造的特性是一致的。  
 1、针对内置类型也会完成浅拷贝  
 2、针对自定义类型,他会调用它的赋值运算符重载完成拷贝


**总结一下编译器默认生成的成语函数:**  
 1、构造和析构的特性是类似的,我们不写编译器对内置类型不做处理,自定义类型调用他的构造函数和析构函数  
 2、拷贝构造和赋值重载特性是类似的,内置类型会完成浅拷贝,自定义类型会调用它们的拷贝构造和赋值重载运算符


**学了重载运算符后,简单实现一个日期类,进一步加深对重载运算符的理解**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/6e7756e5bcba4631972e80fb87bd799a.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASVTojqvmiY7nibk=,size_18,color_FFFFFF,t_70,g_se,x_16#pic_center)


### 日期类的实现


类声明:



#pragma once
#include
using namespace std;
class Date
{
public:
Date(int year, int month, int day);

//日期加天数/减天数
Date operator+(int day);
Date& operator+=(int day);
Date operator-(int day);
Date& operator-=(int day);

//自增
Date& operator++();
Date operator++(int);
Date& operator--();
Date operator--(int);

//日期关系比较
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);
//日期加减日期
int operator-(const Date& d);
//显示日期
void showDate();

private:
int _year;
int _month;
int _day;
};


类成员函数实现:



inline int GetMonthDay(int year, int month)
{
static int arr[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
int day = arr[month];
//四年一润,百年不润,四百年一润
if (month == 2 && year % 4 == 0 && year % 100 != 0 || year % 400 == 0)
{
day = 29;
}

return day;

}



> 
> 针对于频繁调用的函数加上内联,防止频繁开辟栈帧,由于每次开辟一个栈帧这个栈帧都会去创建一个数组,必然是会有消耗的,所以数组改成静态的更适合
> 
> 
> 



Date::Date(int year, int month, int day)
{
//检查年月日是否是合法的
if (year >= 0 &&
month > 0 && month < 13 &&
day <= GetMonthDay(year, month))
{
_year = year;
_month = month;
_day = day;
}
}


#### 加减法运算符重载



> 
> 创建日期类对象的构造函数,需要做一定的检查,防止出现逻辑错误
> 
> 
> 



Date& Date::operator-=(int day)
{
//如果day是负数的情况
if (day < 0)
{
//负负得正
_day += -day;
//处理不合法的天
while (_day > GetMonthDay(_year, _month))
{
_day -= GetMonthDay(_year, _month);
_month++;
if (_month > 12)
{
_month = 1;
_year++;
}
}
}
//day是正数的情况
else
{
//合计天数,天满了向月借,月满了向年借
_day -= day;
while (_day <= 0)
{
_month–;
if (_month == 0)
{
_year–;
_month = 12;
}
_day += GetMonthDay(_year, _month);
}
}
//返回处理后的日期对象

return \*this;

}



> 
> 重载operator-=运算符,使非法日期变得合法,加法进位思想
> 
> 
> 


**优化**  
 但是实现这么一个重载运算符难免会觉得代码长,进一步优化让他简短,提高我们程序的复用性



Date& Date::operator-=(int day)
{
//如果day是负数的情况
if (day < 0)
{
//复用operator+=接口
*this += -day;
}
//day是正数的情况
else
{
//合计天数,天满了向月借,月满了向年借
_day -= day;
while (_day <= 0)
{
_month–;
if (_month == 0)
{
_year–;
_month = 12;
}
_day += GetMonthDay(_year, _month);
}
}
//返回处理后的日期对象
return *this;
}


**重载operator+=运算符**



> 
> 类似于之前的代码,加法进位思想
> 
> 
> 



Date& Date::operator+=(int day)
{
//对可能会存在非法的时间处理
if (day < 0)
{
_day += day;
while (_day <= 0)
{
_month–;
if (_month == 0)
{
_month = 12;
_year–;
}
_day += GetMonthDay(_year, _month);
}
}
else
{
_day += day;
while (_day > GetMonthDay(_year, _month))
{
_day -= GetMonthDay(_year, _month);
_month++;
if (_month > 12)
{
_month = 1;
_year++;
}
}
}
return *this;
}


**同样的重载operator+=运算符也是,需要区分正负数,如果day存在负数的情况可能会存在错误,实际上if (day < 0)这一小块也可以复用之前的operator-=**



Date& Date::operator+=(int day)
{
if (day < 0)
{
//复用operator-=运算符
*this -= -day;
}
else
{
//处理日期,使日期变得合法
_day += day;
while (_day > GetMonthDay(_year, _month))
{
_day -= GetMonthDay(_year, _month);
_month++;
if (_month > 12)
{
_month = 1;
_year++;
}
}
}
//返回处理后的日期对象
return *this;
}


前置++和后置++都是完成一个自增的操作,区别是自增前和自增后,前置++返回的是自增后的值,而后置++返回的是自增前的值,++完了才自增,它们的运算符是一样的,函数名就是一样的,所以为了同时存在,这里会使用到函数重载,这里使用int占位,实际上这个占位符并没有多大作用,只是为了取到函数重载的意义



//前置++
Date& Date::operator++()
{
//复用operator+=运算符
return *this += 1;
}

//后置++
Date Date::operator++(int)
{
//复用operator+=运算符
Date tmp(*this);
*this += 1;
//tmp出了作用域就销毁了,会调用拷贝构造函数创建一个临时对象,最后返回临时对象
return tmp;
}


前置- -和后置- - 运算符重载,跟前面的类似,不做细讲



//前置–
Date& Date::operator–()
{
//复用operator–运算符
return *this -= 1;
}
//后置–
Date Date::operator–(int)
{
//复用operator–运算符
Date tmp(*this);
*this -= 1;
//返回拷贝构造出来的临时对象
return tmp;
}


![在这里插入图片描述](https://img-blog.csdnimg.cn/4dcc5ae3125f481b93fc41b31cedb28a.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASVTojqvmiY7nibk=,size_20,color_FFFFFF,t_70,g_se,x_16)


#### 关系运算符重载,比较两个日期类对象的大小



> 
> 逻辑简单,复用处理就行
> 
> 
> 



bool Date::operator>(const Date& d)
{
//年大比年
if (_year > d._year)
{
return true;
}
else
{
//月大比月
if (_month > d._month)
{
return true;
}
//月相等比天
else if (_month == d._month)
{
if (_day > d._day)
{
return true;
}
}
}
//都不满足就是假
return false;
}

bool Date::operator==(const Date& d)
{
//年月日都相同
return _year == d._year
&& _month == d._month
&& _day == d._day;
}

bool Date::operator>=(const Date& d)
{
//复用> 和==重载后的运算符
if (*this > d || *this == d)
{
return true;
}
else
{
return false;
}
}

bool Date::operator<(const Date& d)
{
//不>=就是小于,取反就行
if (!(*this >= d))
{
return true;
}
else
{
return false;
}
}

bool Date::operator<=(const Date& d)
{
//不>就是小于等于,取反就行
if (!(*this > d))
{
return true;
}
else
{
return false;
}
}

bool Date::operator!=(const Date& d)
{
//不==就是!=,取反就行
if (!(*this == d))
{
return true;
}
else
{
return false;
}
}


**实现日期对象减日期对象的重载运算符**



int Date::operator-(const Date& d)
{
//假设this最大,d最小
Date max = *this;
Date min = d;
int flag = 1;
//如果this小,d大就修正
if (*this < d)
{
max = d;
min = *this;
//符号位
flag = -1;
}
//统计天数
int n = 0;
while (min != max)
{
min++;
n++;
}
//符号处理
return flag * n;
}


## const成员




### 一、网安学习成长路线图


网安所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/aa7be04dc8684d7ea43acc0151aebbf1.png)


### 二、网安视频合集


观看零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/f0aeee2eec7a48f4ad7d083932cb095d.png)


### 三、精品网安学习书籍


当我学到一定基础,有自己的理解能力的时候,会去阅读一些前辈整理的书籍或者手写的笔记资料,这些笔记详细记载了他们对一些技术点的理解,这些理解是比较独到,可以学到不一样的思路。  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/078ea1d4cda342f496f9276a4cda5fcf.png)


### 四、网络安全源码合集+工具包


光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/e54c0bac8f3049928b488dc1e5080fc5.png)


### 五、网络安全面试题


最后就是大家最关心的网络安全面试题板块  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/15c1192cad414044b4dd41f3df44433d.png)![在这里插入图片描述](https://img-blog.csdnimg.cn/b07abbfab1fd4edc800d7db3eabb956e.png)  



**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化资料的朋友,可以点击这里获取](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 9
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值