当前位置: 首页 > wzjs >正文

个人做电子商务网站备案网站开发工程师

个人做电子商务网站备案,网站开发工程师,如何做招聘网站的数据分析,免费h5模板都从哪里下载目录 1. 类的默认成员函数 2. 构造函数 3.析构函数 4.拷贝构造函数 5.赋值运算符重载 5.1运算符重载 5.2赋值运算符重载 6.取地址运算符重载 6.1 const成员函数 6.2 取地址运算符重载 7.日期类(Date)实现 1. 类的默认成员函数 默认成员函数就…

目录

1. 类的默认成员函数

2. 构造函数

3.析构函数

4.拷贝构造函数

5.赋值运算符重载

5.1运算符重载

5.2赋值运算符重载

6.取地址运算符重载

6.1 const成员函数

6.2 取地址运算符重载

7.日期类(Date)实现


1. 类的默认成员函数

默认成员函数就是⽤⼾没有显式实现,编译器会⾃动⽣成的成员函数称为默认成员函数。⼀个类,当不写的情况下编译器会默认⽣成以下6个默认成员函数,构造函数,析构函数,拷贝构造函数,赋值运算符重载,后面移动构造和移动赋值本章不作叙述
对于默认成员函数,虽然编译器能够自动生成,但是大部分情况下还是需要自己动手实现,当默认成员函数 不写时,编译器默认⽣成的函数⾏为是什么,是否满⾜需求,编译器默认⽣成的函数不满⾜需求时,就需要⾃⼰实现

2. 构造函数

1. 函数名与类名相同。
2. ⽆返回值。 (返回值啥都不需要给,也不需要写void,c++规定)
3. 对象实例化时系统会⾃动调⽤对应的构造函数
4. 构造函数可以重载。
用Date(日期)类举例
class Date
{
public:// 1.无参构造函数Date(){_year = 1;_month = 1;_day = 1;}// 2.带参构造函数Date(int year, int month, int day){_year = year;_month = month;_day = day;}// 3.全缺省构造函数Date(int year=1, int month=1, int day=1){_year = year;_month = month;_day = day;}void Print(){cout << _year << "/" << _month << "/" << _day << endl;}
private:int _year;int _month;int _day;
};int main()
{Date d1;//调用的是无参的d1.Print();Date d2(2025, 1, 1); // 调⽤带参的构造函数// 注意:如果通过⽆参构造函数创建对象时,对象后⾯不⽤跟括号,
//否则编译器⽆法区分这⾥是函数声明还是实例化对象//Date d3();return 0;
}

注意:全缺省的与无参的不能同时存在

5. 如果类中没有显式定义构造函数,则C++编译器会⾃动⽣成⼀个⽆参的默认构造函数,⼀旦⽤⼾显式定义编译器将不再⽣成。
6. ⽆参构造函数、全缺省构造函数、我们不写构造时编译器默认⽣成的构造函数 ,都叫做默认构造函数。但是这三个函数有且只有⼀个存在,不能同时存在。⽆参构造函数和全缺省构造函数虽然构成函数重载,但是调⽤时会存在歧义。注意默认构造函数不是编译器默认⽣成那个叫默认构造,实际上⽆参构造函数、全缺省构造函数也是默认构造,总结⼀下就是不传实参就可以调⽤的构造就叫默认构造。
7. 我们不写,编译器默认⽣成的构造,对内置类型成员变量的初始化没有要求,也就是说是是否初始化是不确定的,看编译器。对于⾃定义类型成员变量,要求调⽤这个成员变量的默认构造函数初始化。如果这个成员变量,没有默认构造函数,那么就会报错,解决这种方法就需要初始化列表,本章不作叙述
说明:C++把类型分成内置类型(基本类型)和⾃定义类型。内置类型就是语⾔提供的原⽣数据类型, 如:int/char/double/指针等,⾃定义类型就是我们使⽤class/struct等关键字⾃⼰定义的类型。

对于自定义类型来说,构造函数尽量自己手动写,来看看栈的构造

class Stack
{
public:Stack(int n = 4){_a = (STDataType*)malloc(sizeof(STDataType) * n);if (nullptr == _a){perror("malloc申请空间失败");return;}_capacity = n;_top = 0;}// ...
private:STDataType * _a;size_t _capacity;size_t _top;
};
int main()
{Stack d1;return 0;
}

这里构造的话如果没有参数传进去,构造函数一定要写出全缺省,否则无法调用构造函数

对于自定义类型来说,有点类型就可以不需要手动写构造函数,eg:两个栈实现队列

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;}// ...
private:STDataType * _a;size_t _capacity;size_t _top;
};
// 两个Stack实现队列
class MyQueue
{
public://编译器默认⽣成MyQueue的构造函数调⽤了Stack的构造,完成了两个成员的初始化
private:Stack pushst;Stack popst;
};
int main()
{MyQueue mq;return 0;
}

此时对于MyQueue类来说,调用的是Stack的构造

3.析构函数

析构函数与构造函数功能相反,析构函数不是完成对对象本⾝的销毁,⽐如局部对象是存在栈帧的,函数结束栈帧销毁,他就释放了,不需要我们管,C++规定对象在销毁时会⾃动调⽤析构函数,完成对象中资源的清理释放⼯作。析构函数的功能类⽐我们之前Stack实现的Destroy功能,⽽像Date(日期类)没有Destroy,其实就是没有资源需要释放,所以严格说Date是不需要析构函数的。
析构函数的特点:
1. 析构函数名是在类名前加上字符 ~。
2. ⽆参数⽆返回值。 (这⾥跟构造类似,也不需要加void)
3. ⼀个类只能有⼀个析构函数。若未显式定义,系统会⾃动⽣成默认的析构函数。
4. 如果类中没有申请资源时,析构函数可以不写,直接使⽤编译器⽣成的默认析构函数,如Date;如果默认⽣成的析构就可以⽤,也就不需要显⽰写析构,如MyQueue;但是有资源申请时,⼀定要⾃⼰写析构,否则会造成资源泄漏,如Stack。
4. 对象⽣命周期结束时,系统会⾃动调⽤析构函数。
5.⼀个局部域的多个对象,C++规定后定义的先析构
用Stack举例
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(){_a = nullptr;_capacity = _top = 0;}
private:STDataType * _a;size_t _capacity;size_t _top;
};
int main()
{Stack d1;//后析构Stack d2;//先析构return 0;
}

对于MyQueue编译器默认的析构函数调用的是Stack的析构

6. 跟构造函数类似,我们不写编译器⾃动⽣成的析构函数对内置类型成员不做处理,⾃定类型成员会调⽤它的析构函数。
7. 需要注意的是我们显⽰写析构函数,对于⾃定义类型成员也会调⽤它的析构,也就是说⾃定义类型成员⽆论什么情况都会⾃动调⽤析构函数。
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(){_a = nullptr;_capacity = _top = 0;}
private:STDataType * _a;size_t _capacity;size_t _top;
};
// 两个Stack实现队列
class MyQueue
{
public://编译器默认⽣成MyQueue的构造函数调⽤了Stack的构造,完成了两个成员的初始化~MyQueue()//即使这里写了也会调⽤编译器默认的析构,防止析构函数没有完全清空资源,
//如下,函数体内即使没有写相关清理资源的代码,
// 由于析构函数的特性,编译器会调用它自己生成的默认的析构,来清理资源{cout << "~MyQueue()" << endl;}
private:Stack pushst;Stack popst;
};
int main()
{Stack d1;//后析构Stack d2;//先析构return 0;
}

4.拷贝构造函数

如果⼀个构造函数的第⼀个参数是⾃⾝类类型的引⽤,且任何额外的参数都有缺省·值,则此构造函数也叫做拷⻉构造函数,拷⻉构造是⼀个特殊的构造函数。
1. 拷⻉构造函数是构造函数的⼀个重载。
2. 拷⻉构造函数第一个参数必须是类类型对象的引⽤,C++的规定,传值传参要调用拷贝构造, 使⽤传值⽅式编译器直接报错,因为语法逻辑上会引发⽆穷递归调⽤。
用Date举例
class Date
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}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;
};
int main()
{Date d1;Date d2(d1);//利用拷贝构造// 也可以这样写,这⾥也是拷⻉构造Date d3 = d1;return 0;
}

如果拷贝构造函数参数没有用引用的话,d1传值给拷贝构造函数时会回生成一个拷贝构造函数,此时进入这个生成出的拷贝构造函数,又因为传值的原因又会生成一个拷贝构造函数,此时就会陷入无限递归

3. C++规定⾃定义类型对象进⾏拷⻉⾏为必须调⽤拷⻉构造,所以这⾥⾃定义类型传值传参和传值返回都会调⽤拷⻉构造。
4. 若未显式定义拷⻉构造,编译器会⽣成⾃动⽣成拷⻉构造函数。⾃动⽣成的拷⻉构造对内置类型成员变量会完成值拷⻉/浅拷⻉(⼀个字节⼀个字节的拷⻉),对⾃定义类型成员变量会调⽤它的拷⻉构造。
5. 像Date这样的类成员变量全是内置类型且没有指向什么资源,编译器⾃动⽣成的拷⻉构造就可以完成需要的拷⻉,所以不需要我们显⽰实现拷⻉构造。像Stack这样的类,虽然也都是内置类型,但是_a指向了资源,编译器⾃动⽣成的拷⻉构造完成的值拷⻉/浅拷⻉不符合我们的需求,所以需要我们⾃⼰实现深拷⻉(对指向的资源也进⾏拷⻉)。像MyQueue这样的类型内部主要是⾃定义类型Stack成员,编译器⾃动⽣成的拷⻉构造会调⽤Stack的拷⻉构造,也不需要我们显⽰实现 MyQueue的拷⻉构造。
来看看Stack拷贝构造
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(const Stack& st){// 需要对_a指向资源创建同样⼤的资源再拷⻉值_a = (STDataType*)malloc(sizeof(STDataType) * st._capacity);if (nullptr == _a){perror("malloc申请空间失败!!!");return;}memcpy(_a, st._a, sizeof(STDataType) * st._top);_top = st._top;_capacity = st._capacity;}~Stack(){cout << "~Stack()" << endl;free(_a);_a = nullptr;_top = _capacity = 0;}
private:STDataType* _a;size_t _capacity;size_t _top;
};
int main()
{Stack d1;//后析构Stack d2;//先析构return 0;
}

如果这里不写拷贝构造函数,使用编译器的拷贝构造函数,此时d1和d2的_a都指向同一块空间,此时为浅拷贝,析构时会析构两次,程序崩溃,此时就需要手动改变d2的_a的指向,同时还要把d1中_a的值拷贝给d2,此时就是一个深拷贝

这⾥有⼀个⼩技巧,如果⼀个类显⽰实现了析构并释放资源,那么他就需要显⽰写拷⻉构造,否则就不需要。
6. 传值返回会产⽣⼀个临时对象调⽤拷⻉构造,传值引⽤返回,返回的是返回对象的别名(引⽤),没有产⽣拷⻉。但是如果返回对象是⼀个当前函数局部域的局部对象,函数结束就销毁了,那么使⽤引⽤返回是有问题的,这时的引⽤相当于⼀个野引⽤,类似⼀个野指针⼀样。传引⽤返回可以减少拷⻉,但是⼀定要确保返回对象,在当前函数结束后还在,才能⽤引⽤返回。
用Date举例
class Date
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}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 Func1(Date d)
{cout << &d << endl;d.Print();
}
Date& Func2()
{Date tmp(2024, 7, 5);tmp.Print();return tmp;
}
int main()
{Date d1(2024, 7, 5);// C++规定⾃定义类型对象进⾏拷⻉⾏为必须调⽤拷⻉构造,所以这⾥传值传参要调⽤拷⻉构造// 这⾥的d1传值传参给d要调⽤拷⻉构造完成拷⻉,传引⽤传参可以较少这⾥的拷⻉Func1(d1);cout << &d1 << endl;// Func2返回了⼀个局部对象tmp的引⽤作为返回值// Func2函数结束,tmp对象就销毁了,相当于了⼀个野引⽤Date ret = Func2();ret.Print();return 0;
}
//t

5.赋值运算符重载

5.1运算符重载

1.当运算符被⽤于类类型的对象时,C++语⾔允许我们通过运算符重载的形式指定新的含义。C++规定类类型对象使⽤运算符时,必须转换成调⽤对应运算符重载,若没有对应的运算符重载,则会编译报错。
2.运算符重载是具有特名字的函数,他的名字是由 operator 和后⾯要定义的运算符共同构成。和其他函数⼀样,它也具有其返回类型和参数列表以及函数体。
3.重载运算符函数的参数个数和该运算符作⽤的运算对象数量⼀样多。⼀元运算符有⼀个参数,⼆元运算符有两个参数,⼆元运算符的左侧运算对象传给第⼀个参数,右侧运算对象传给第⼆个参数。
4.操作符⾄少有⼀个类类型参数,不能通过运算符重载改变内置类型对象的含义,如: int operator+(int x, int y)
用Date举例
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;}
private:int _year;int _month;int _day;
};
bool operator==(const Date& d1, const Date& d2)
{return d1._year == d2._year&& d1._month == d2._month&& d1._day == d2._day;
}

这里我们访问了Date类的私有变量,会出错,因此可以重载为成员函数

5.如果⼀个重载运算符函数是成员函数,则它的第⼀个运算对象默认传给隐式的this指针,因此运算符重载作为成员函数时,参数⽐运算对象少⼀个。
6.运算符重载以后,其优先级和结合性与对应的内置类型运算符保持⼀致。
7.不能通过连接语法中没有的符号来创建新的操作符:⽐如operator@。
上述代码可以写成
class Date
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}bool operator==(const Date& d)//第一个参数是this{return _year == d._year&& _month == d._month&& _day == d._day;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1(2000,1,1);Date d2(2010,10,1);operator==(d1, d2);//可以显示调用d1 == d2;//也可以和内置类型一样使用return 0;
}
8.  .*    ::    sizeof    ?:   .      注意以上5个运算符不能重载。
::   是域作用访问限定符
sizeof 计算空间大小
?:   是三目运算符
.         是用类的成员函数
对于 .*  这个运算符
class A
{
public:void func(){cout << "A::func()" << endl;}
};
typedef void(A::* PF)(); //成员函数指针类型
int main()
{// C++规定成员函数要加&才能取到函数指针PF pf = &A::func;A obj;//定义A类对象obj// 对象调⽤成员函数指针时,使⽤.*运算符(obj.*pf)();return 0;
}
9.⼀个类需要重载哪些运算符,根据这个类的使用情况来决定的
10.重载++运算符时,有前置++和后置++,运算符重载函数名都是operator++,⽆法很好的区分。 C++规定,后置++重载时,增加⼀个int形参,跟前置++构成函数重载,⽅便区分。
	//前置++Date& operator++(){*this += 1;return *this;}//后置++Date operator++(int)//这里可以不用写变量名{Date tmp = *this;*this += 1;return tmp;}

这里的+=是默认已经重载好了,但是这里没有实现,下面日期类中会进行实现

11.重载<<和>>时,需要重载为全局函数,因为重载为成员函数,this指针默认抢占了第⼀个形参位置,第⼀个形参位置是左侧运算对象,调⽤时就变成了 对象<<cout,不符合使⽤习惯和可读性。重载为全局函数把ostream/istream放到第⼀个形参位置就可以了,第⼆个形参位置当类类型对象。
	//类内重载>>和<<ostream& operator<<(ostream& out){out << _year <<"年"<< _month <<"月"<< _day<<"日";return out;}//如果在类内重载,第一个参数是this,那使用<<重载就会如下//Date d1;//d1<<cout这明显不符合我们使用cout的习惯//因此>>和<<的重载在全局进行

在全局域实现

ostream& operator<<(ostream& out, const Date& d)
{out << d._year << "年" << d._month << "月" << d._day << "日" << endl;return out;
}//返回是ostream&使cout能够连续使用
//eg:cout>>>d1>>d2>>d3
istream& operator>>(istream& in, Date& d)
{cout << "请依次输入年月日:>";in >> d._year >> d._month >> d._day;return in;
}

当在全局重载的时候怎么访问类类型的变量?

1.把变量改为公有

2.使用友元函数

友元函数这里不做过多解释,只说明用法

在函数声明或者类声明的前⾯加friend,并且把友元声明放到⼀个类的⾥⾯,此时这个函数就可以访问到类中的变量
class Date
{friend ostream& operator<<(ostream& out, const Date& d);//设立友元friend istream& operator>>(istream& in, Date& d);
public:private:int _year;int _month;int _day;
};
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;return in;
}

5.2赋值运算符重载

赋值运算符重载是⼀个默认成员函数,⽤于完成两个已经存在的对象直接的拷⻉赋值,这⾥要注意跟拷⻉构造区分,拷⻉构造⽤于⼀个对象拷⻉初始化给另⼀个要创建的对象。
1. 赋值运算符重载是⼀个运算符重载,规定必须重载为成员函数。赋值运算重载的参数建议写成const当前类类型引⽤,否则会传值传参会有拷⻉
2. 有返回值,建议写成当前类类型引⽤,引⽤返回可以提⾼效率,有返回值⽬的是为了⽀持连续赋值场景。
用Date举例
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;}// 传引⽤返回减少拷⻉// const防止d被修改// d1 = d2;Date& operator=(const Date& d){// 检查⾃⼰给⾃⼰赋值的情况if (this != &d){_year = d._year;_month = d._month;_day = d._day;}// d1 = d2表达式的返回对象应该为d1,也就是*thisreturn *this;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1(2024, 7, 5);Date d2(2024, 7, 6);Date d3;//此时d1,d3应经创建好了,d3赋值给d1d3= d1 = d2;//从右向左// 需要注意这⾥是拷⻉构造,不是赋值重载Date d4 = d1;return 0;
}

3. 没有显式实现时,编译器会⾃动⽣成⼀个默认赋值运算符重载,默认赋值运算符重载⾏为跟默认构造函数类似,对内置类型成员变量会完成值拷⻉/浅拷⻉(⼀个字节⼀个字节的拷⻉),对⾃定义类型成员变量会调⽤他的拷⻉构造。
4. 像Date这样的类成员变量全是内置类型且没有指向什么资源,编译器⾃动⽣成的赋值运算符重载就可以完成需要的拷⻉,所以不需要我们显⽰实现赋值运算符重载。像Stack这样的类,虽然也都是内置类型,但是_a指向了资源,编译器⾃动⽣成的赋值运算符重载完成的值拷⻉/浅拷⻉不符合我们的需求,所以需要我们⾃⼰实现深拷⻉(对指向的资源也进⾏拷⻉)。像MyQueue这样的类型内部主要是⾃定义类型Stack成员,编译器⾃动⽣成的赋值运算符重载会调⽤Stack的赋值运算符重载, 也不需要我们显⽰实现MyQueue的赋值运算符重载。
这⾥有⼀个⼩技巧,如果⼀个类显⽰实现了析构并释放资源,那么他就需要显⽰写赋值运算符重载,否则就不需要。

6.取地址运算符重载

6.1 const成员函数

1.将const修饰的成员函数称之为const成员函数,const修饰成员函数放到成员函数参数列表的后
⾯。
2.const实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进⾏修改。
class Date
{
public:void Print(){cout << _year << "/" << _month << "/" << _day;}
private:int _year;int _month;int _day;
};
int main()
{const Date d1;d1.Print();//此时d1是由const修饰Date的对象,//无法访问类中无const修饰的函数return 0;
}

此时在函数声明和定义后面加上const就能访问

void Print()const
{cout << _year << "/" << _month << "/" << _day;
}

对于加了const的Print函数,此时this中的成员变量无法修改

void Print()const
{//_year++无法改变cout << _year << "/" << _month << "/" << _day;
}

对于没有用const修饰的对象,也能访问const修饰的函数,这其实是一种权限的缩小

class Date
{
public:void Print()const{cout << _year << "/" << _month << "/" << _day;}
private:int _year;int _month;int _day;
};
int main()
{const Date d1;d1.Print();Date d2;d2.Print();//也能访问const修饰的函数return 0;
}

当函数内中成员变量不作修改时,可以用const修饰函数

6.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;
};

7.日期类(Date)实现

日期类主要就是对日期的一些使用,例如某一天与另一天相隔多久,某一天后100天或前100天是什么时候

Date.h

#pragma once
#include<iostream>
using namespace std;
#include<assert.h>
class Date
{friend ostream& operator<<(ostream& out, const Date& d);friend istream& operator>>(istream& in, Date& d);
public:Date(int year = 1900, int moth = 1, int day = 1);//初始化bool CheckDate() const;//判断写入的日期是否合法int GetMonthDay(int year, int moth)const//获取某一年中某个月的天数{//由于这个函数经常要用,实现在类里,相当inlineassert(moth > 0 && moth < 13);//使用数组来确定天数,由于要返回数组的内容,设置为静态成员static int monthDayArray[13] = { -1, 31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31 };//判断闰年if (moth == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))){return 29;}return monthDayArray[moth];}//判断日期大小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;//对日期进行运算Date operator+(int day) const;Date& operator+=(int day);Date operator-(int day) const;Date& operator-=(int day);Date operator++(int);Date& operator++();Date operator--(int);Date& operator--();//两个日期间的差值int operator-(const Date& d) const;
private:int _year;int _moth;int _day;
};
ostream& operator<<(ostream& out, const Date& d);//输出
istream& operator>>(istream& in, Date& d);//输入

Date.cpp

#include"Date.h"
bool Date::CheckDate() const
{if (_month < 1 || _month > 12|| _day < 1 || _day > GetMonthDay(_year, _month)){return false;}else{return true;}
}
Date::Date(int year , int moth, int day)//初始化
{_year = year;_month = moth;_day = day;if (!CheckDate()){cout << "非法日期:";Print();}
}
Date& Date::operator=(const Date& d)
{// 检查⾃⼰给⾃⼰赋值的情况if (this != &d){_year = d._year;_month = d._month;_day = d._day;}// d1 = d2表达式的返回对象应该为d1,也就是*thisreturn *this;
}
//判断日期大小,可以不需要实现每个函数,有的函数可以复用
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;
}
bool Date::operator>=(const Date& d) const
{return !(*this < d);//复用
}
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 _year == d._year&& _month == d._month&& _day == d._day;
}
bool Date::operator!=(const Date& d) const
{return !(*this == d);
}
//对日期进行运算
//   d1+=day d1本身改变
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+day  d1本身不改变
Date Date::operator+(int day) const
{Date tmp = *this;tmp += day;return tmp;
}
//上述+复用+=,同样+=也可复用+,
// 不过+=(-=)复用+(-)会导致增加三次拷贝,
//对于下面减操作,使用-=复用-Date Date::operator-(int day) const//传值返回一次拷贝
{Date tmp = *this;//赋值运算,拷贝一次tmp._day -= day;while (tmp._day <= 0){--tmp._month;if (tmp._month == 0){tmp._month = 12;--tmp._year;}tmp._day += GetMonthDay(tmp._year, tmp._month);}return tmp;
}
Date& Date::operator-=(int day)
{*this = *this - day;//表达式运算,拷贝一次return *this;
}
//后置++
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;
}
Date& Date::operator--()
{*this -= 1;return *this;
}
//两个日期间的差值
int Date::operator-(const Date& d) const
{int flag = 1;//设定正负Date max = *this;Date min = d;if (*this < d){max = d;min = *this;flag = -1;}int n = 0;while (min != max){++min;++n;}return n * flag;
}
void Date::Print()
{cout << *this;
}
ostream& operator<<(ostream& out, const Date& d)
{out << d._year << "年" << d._month << "月" << d._day << "日" << endl;return out;
}
istream& operator>>(istream& in, Date& d)
{while (1){cout << "请依次输入年月日:>";in >> d._year >> d._month >> d._day;if (!d.CheckDate()){cout << "输入日期非法:";d.Print();cout << "请重新输入!!!" << endl;}else{break;}}return in;
}

http://www.dtcms.com/wzjs/112122.html

相关文章:

  • 云浮新兴县做网站seo排名优化软件有
  • 普陀区网站建百度搜索关键词怎么刷上去
  • 网站修改器最近一个月的热点事件
  • 开放平台是干什么的seo推广公司教程
  • 大连招聘网最新招聘上海短视频seo优化网站
  • wordpress指定域名优化网络的软件下载
  • 地税网站如何做税种确认今日头条最新新闻消息
  • 中国机械工业网谷歌seo网络公司
  • 百度 网站地图怎么做制作网站需要什么
  • 苏州有哪些做网站公司好百度推广优化方案
  • 西安电商网站建设搜狗收录查询
  • 韩国设计教程网站合肥网站推广优化
  • 手机做任务的网站有哪些网址外链平台
  • 网站打开的速度很慢应该怎么做长尾关键词搜索网站
  • 一级域名的网站怎么做互联网营销师培训多少钱
  • 怎么做漫画网站微信朋友圈广告推广
  • 网站设计团队网站建设维护
  • 湖南网站建设费用星沙网站优化seo
  • 彭州做网站的公司百度游戏中心官网
  • 做我女朋友网站在哪个网站可以免费做广告
  • mac网站建设创建数据库网站关键词上首页
  • 哈尔滨网站设计快速建站广州网站快速排名
  • 网站建设要素的核心内容二级域名注册
  • 一个网站两个数据库seo建站是什么
  • 网上购物平台排名前十名sem和seo有什么区别
  • 做汽车内饰皮革批发的网站互联网舆情
  • 易语言做网站简单教程十大网络推广公司排名
  • 顺德网站建设价格如何在百度上做广告
  • 网站个人备案步骤互联网平台公司有哪些
  • thinkphp5做网站产品seo是什么意思