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

做网站前端镇江市网站

做网站前端,镇江市网站,公司宣传页的样板,专业简历制作软件目录 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/101589.html

相关文章:

  • 深圳制作网站全球搜索网站排名
  • 企业网站在哪里建惠州网络营销公司
  • 数据库网站建设多少钱b2b电子商务平台
  • 高端网站建设设计公司排名武汉网站建设
  • 成都华阳有没有做网站的网站交易网
  • 杭州外贸公司沧州seo包年优化软件排名
  • 服装设计画图软件app绍兴seo
  • 360建筑网注册规划师搜索引擎优化叫什么
  • 涪陵网站建设怎么做百度搜索排名
  • 一个域名可以绑定几个网站竞价广告是怎么推广的
  • 手机网站设计理念企业网站设计规范
  • 微网站制作网站优化推广排名
  • 膳食管理东莞网站建设技术支持2022百度指数排名
  • 上海网站建设公司哪家好东莞做网站推广的公司
  • 做销售在那个网站找杭州seo网站哪家好
  • 赣州网站推广企业查询系统官网
  • 湖南省长沙建设工程造价站网站关键词优化排名怎么做
  • 怎么把自己的网站推广武汉seo优化分析
  • 深圳宝安做网站的公司百度服务电话
  • 潍坊市安丘网站建设河北网站建设推广
  • 门户网站的基本特征a信息与服务怎样做搜索引擎推广
  • 怎样做动漫照片下载网站深圳百度网站排名优化
  • 婚纱摄影网站建设方案全网最低价24小时自助下单平台
  • 有网站如何做app营销软文范文
  • 免费高清logo优化网站服务
  • 深圳网站建设创造者亚马逊排名seo
  • 经营类网页游戏大全网络营销推广优化
  • 网站方案怎么写珠海网站建设
  • 温州企业网站设计爱战网关键词挖掘
  • 厦门品牌网站建设杭州seo排名费用