网站图片 原则,企业网站的搭建流程,怎么给自己的网站做扫描码,wordpress怎么改登陆地址目录
一 . 赋值运算符重载
1.1 运算符重载
1.2 赋值运算符重载
1.3 日期类实现 1.3.1 比较日期的大小 : 1.3.2 日期天数 :
1.3.3 日期 - 天数 :
1.3.4 前置/后置
1.3.5 日期 - 日期 1.3.6 流插入 和 流提取
二 . 取地址运算符重载
2.1 const…目录
一 . 赋值运算符重载
1.1 运算符重载
1.2 赋值运算符重载
1.3 日期类实现 1.3.1 比较日期的大小 : 1.3.2 日期天数 :
1.3.3 日期 - 天数 :
1.3.4 前置/后置
1.3.5 日期 - 日期 1.3.6 流插入 和 流提取
二 . 取地址运算符重载
2.1 const 成员函数
2.2 取地址运算符重载 回顾借助 三道选择题深刻回顾以下 上一章节的内容类和对象(中)-CSDN博客
一 . 下列关于构造函数的描述 正确 的是( )
A.构造函数可以声明返回类型
B.构造函数不可以用private修饰
C.构造函数必须与类名相同
D.构造函数不能带参数 C A . 构造函数不能声明返回类型void 也不可以 B . 可以的 只不过不能直接实例化对象了 D . 构造函数不光可以带参数还可以有多个构造函数构成重载 二 . 在函数F中本地变量a和b的构造函数(constructor)和析构函数(destructor)的调用顺序是: ( )
Class A;
Class B;
void F() {
A a; B b; }
A.b构造 a构造 a析构 b析构
B.a构造 a析构 b构造 b析构
C.b构造 a构造 b析构 a析构
D.a构造 b构造 b析构 a析构 构造顺序是按照语句的顺序进行构造析构是按照构造的相反顺序进行析构 , 对象析构要在生存作用域结束的时候才进行析构 D 三 . 设已经有A,B,C,D4个类的定义程序中A,B,C,D析构函数调用顺序为
C c;
int main()
{
A a;
B b;
static D d; return 0
}
A.D B A C
B.B A D C
C.C D B A
D.A B D C 1、类的析构函数调用一般按照构造函数调用的相反顺序进行调用但是要注意static对象的存在 因为static改变了对象的生存作用域需要等待程序结束时才会析构释放对象 2、全局对象先于局部对象进行构造 3、局部对象按照出现的顺序进行构造无论是否为static 4、所以构造的顺序为 c a b d 5、析构的顺序按照构造的相反顺序析构只需注意static改变对象的生存作用域之后会放在局部 对象之后进行析构 6、因此析构顺序为B A D C 一 . 赋值运算符重载
1.1 运算符重载 当运算符被用于类 类型的对象时 C语言允许我们通过运算符重载的形式指定新的含义 。 C规定 类类型对象使用运算符时 必须转化成调用对应运算符重载 若没有运算符重载 则会编译报错 。运算符重载时具有特定名字的函数 它的名字是由 operator 和 后面要定义的运算符共同构成 。 和其他函数一样 它也 具有其 返回类型 和 参数列表 以及 函数体 。重载运算符函数和参数个数和该运算符作用的运算对象数量一样多 。 一元运算符有一个参数 二元运算符有两个参数 二元运算符的 左侧运算对象 传给 第一个参数 右侧运算对象 传给 第二个参数。如果一个重载运算符函数是成员函数则它的第一个运算对象默认传给隐式的 this指针因此运算符重载作为成员函数时参数比运算对象少一个。 内置类型运算时 会比较简单 能够直接转化成相应的指令 下面举个例子
int main()
{int i 1, j 3;int ret1 i j;bool ret2 i j;int ret3 i ^ j;return 0;
} 我们调试以下 转到汇编语言 可以看到编译器可以直接转为 add , cmp , xor 指令 但是对于自定义类型 是由程序员自己定义的 需要实现的功能也是由程序员定义的 下面我们举一个日期类的例子 我们的编译器充当的是翻译功能 当需要实现太复杂的对象与对象之间的运算 编译器编不出来 所以我们需要写一个运算符重载函数 实现相应的运算功能 : 如果这样设为公有 成员变量很容易被访问到 很不安全 以下提供三种方法 #define _CRT_SECURE_NO_WARNINGS 1
#include iostream
using namespace std;class Date
{
public:Date(int year, int month, int day){_year year;_month month;_day day;}void Print(){cout _year / _month / _dayendl;}bool operator(const Date x){return _year x._year _month x._month _day x._day;}
private:int _year;int _month;int _day;
};
int main()
{Date d1(2024, 11, 15);Date d2(2024, 11, 30);bool ret1 d1 d2;cout ret1 endl;return 0;
} 运算符重载以后 其优先级和结合性与对应的内置类型运算符保持一致。不能通过连接语法中没有的符号来创建新的操作符 比如operator .* :: sizeof ?: . 注意以上5个运算符不能重载 。 重载操作符至少有一个类 类型参数 不能通过运算符重载改变内置类型对象的含义 如 int operator(int x,int y )一个类需要重载那些运算符 是看那些运算符重载后有意义 比如Date 类 重载 operator- 就有意义 但是重载 opearator 就没有意义 。重载运算符时 有前置 和后置 运算符重载函数名都是operator , 无法很好的区分 。 C规定 后置重载时候 增加一个 int 形参 跟前置 构成函数重载 方便区分 。重载 和 时 需要重载函数为全局函数 因为重载为成员函数 this 指针 默认抢占了第一个形参位置 第一个形参位置是左侧运算符对象 调用时就变成了 对象cout , 不符合使用习惯和可读性 。 重载为全局函数把 ostream/istream 放在第一个形参位置就可以了 第二个形参位置当类型对象 。 .* 应用举例 //.* 举例#define _CRT_SECURE_NO_WARNINGS 1
#includeiostream
using namespace std;
// 编译报错“operator ”必须⾄少有⼀个类类型的形参
int operator(int x, int y)
{return x - y;
}
class A
{
public:void func(){cout A::func() endl;}
};
typedef void(A::* PF)(); //成员函数指针类型
int main()
{// C规定成员函数要加才能取到函数指针PF pf A::func;A obj;//定义ob类对象temp// 对象调⽤成员函数指针时使⽤.*运算符(obj.*pf)();return 0;
} 1.2 赋值运算符重载
赋值运算符重载是一个默认成员函数 用于完成两个 已经存在 的对象直接拷贝赋值 这里要注意跟拷贝构造区分 拷贝构造用于一个对象拷贝初始化给另一个对象 。 赋值运算符重载的特点 : 赋值运算符重载是一个运算符重载 规定必须重载为成员函数 。 赋值运算重载的参数建议写成 const 当前类 类型引用 否则 会 传值传参会有拷贝 。有返回值 且建议写成当前类 类型引用 引用返回可以提高效率 有返回值目的是为了支持连续赋值场景 。没有显式实现时 编译器会自动生成一个默认赋值运算符重载 默认运算符重载行为跟默认构造函数类似 对内置类型成员变量会完成值拷贝 / 浅拷贝一个字节一个字节的拷贝对自定义类型成员变量会调用他的拷贝构造 。 什么时候需要实现赋值重载 ? 如果栈 进行赋值重载时 但是没有进行写赋值重载函数会发生什么情况 #define _CRT_SECURE_NO_WARNINGS 1
#include iostream
using namespace std;class Date
{
public:Date(int year, int month, int day){_year year;_month month;_day day;}//赋值重载 -- 两个都是存在的对象//d2 d1Date 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;
};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;}// st2(st1)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;}// st1 st3// st1 st1;Stack operator(const Stack st){if (this ! st){free(_a);_a (STDataType*)malloc(sizeof(STDataType) * st._capacity);if (nullptr _a){perror(malloc申请空间失败!!!);return *this;}memcpy(_a, st._a, sizeof(STDataType) * st._top);_top st._top;_capacity st._capacity;}return *this;}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;}void Pop(){_a[_top - 1] -1;--_top;}int Top(){return _a[_top - 1];}~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(2024, 11, 20);d1.Print();Date d2(2024, 11, 30);d2.Print();Date d3 d2;d3.Print();Stack st1;st1.Push(1);st1.Push(2);st1.Push(3);st1.Push(4);Stack st2(10);for (size_t i 0; i 10; i){st2.Push(i * 10);}st1 st2;MyQueue q1;MyQueue q2(q1);MyQueue q3;q1 q3;return 0;
} 1.3 日期类实现 为了更好的进行文件管理 我们创建三个文件 Date.cpp , Date.h , test,cpp 日期类的实现 需要结合实际生活中的客观现象 : 比如闰年2月为29天等 1.3.1 比较日期的大小 : bool Date::operator(const Date d)
{if (_year d._year){return true;}else if(_year d._year_month d._month){return true;}else if(_year d._year _month d._month){return _day d._day;}return false;
}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);
}1.3.2 日期天数 : // GetMonthDayint GetMonthDay(int year, int month){static int monthDayArry[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;}return monthDayArry[month];}//
Date Date::operator(int day)
{_day day;while (_day GetMonthDay(_year, _month)){_day - GetMonthDay(_year, _month);//天满进月_month;//月满进年if (_month 13){_month 1;_year;}}return *this;
}//
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._month 1;tmp._year;}}return tmp;
} 与 比较 Date d1 ; Date d2 d1 50; d1 不变(*this) Date d1; Date d2 d1 50; : d1 改变(*this) 可以使用 复用实现
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._month 1;tmp._year;}}return tmp;
}// 复用实现
Date Date::operator(int day)
{*this *this _day;return *this;
} 可以使用 复用实现 :
Date Date::operator(int day)
{_day day;while (_day GetMonthDay(_year, _month)){_day - GetMonthDay(_year, _month);//天满进月_month;//月满进年if (_month 13){_month 1;_year;}}return *this;
}// 复用实现
Date Date::operator(int day)
{Date tmp(*this);tmp day;return tmp;
} 复用实现 的情况好 还是 复用实现 的情况好 对比调用拷贝构造的次数 使用 复用 更好 1.3.3 日期 - 天数 : Date Date::operator-(int day)
{_day - day;while (_day0){//借位--_month;if (_month 0){--_year;_month 12;}_day GetMonthDay(_year, _month);}return *this;
}Date Date::operator-(int day)
{Date tmp(*this);tmp._day - day;while (tmp._day 0){//借位--tmp._month;if (tmp._month 0){--tmp._year;tmp._month 12;}tmp._day GetMonthDay(tmp._year, tmp._month);}return tmp;
} 如果 d1 -100 d2 - -100 在程序中可以得到合理结果吗 运行 --- -28 日不存在 -- 不合理 1 d1 -100 ----- 实际就是 -100 2 ) d2 - -100 ----- 实际就是 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){_month 1;_year;}}return *this;
}Date Date::operator-(int day)
{if (day 0)return *this (-day);_day - day;while (_day0){//借位--_month;if (_month 0){--_year;_month 12;}_day GetMonthDay(_year, _month);}return *this;
}
1.3.4 前置/后置 重载运算符时 有前置 和 后置 运算符重载函数名都是 operator , 无法很好的区分 C规定 后置 重载时 增加一个 int 形参 跟前置 构成函数重载 方便区分 多了一个参数仅仅是为了区分前置和后置 //前置
Date Date::operator()
{*this *this 1;return *this;
}
//后置
Date Date::operator(int)
{Date tmp *this;*this *this 1;return tmp;
}//前置--
Date Date::operator--()
{*this *this - 1;return *this;
}
//后置--
Date Date::operator--(int)
{Date tmp *this;*this *this - 1;return tmp;
} 1.3.5 日期 - 日期 //d1 - d2
int Date::operator-(const Date d)
{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 flag * n;
} 1.3.6 流插入 和 流提取 注意 : 如果 的运算符重载写在成员函数里 第一个参数一定是this 那么插入操作就必须写成 d1cout , 代码可读性大大降低 所以我们需要把 的运算符重载 写在类外 但是这样会导致私有的成员变量访问异常所以我们在类内 把运算符重载函数设为友元函数 // 流插入 读
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;
}
但是 如果我输入2023年2月29日 不合法的日期 是否可以正常打印呢 那就意味着我们还需要写一个 合法检查函数 控制在输入 和 构造函数 必须是合法的日期 bool Date::CheckDate()
{if (_month 1 || _month 12|| _day 1 || _day GetMonthDay(_year, _month)){return false;}else{return true;}
}Date::Date(int year, int month, int day)
{_year year;_month month;_day day;if (!CheckDate()){cout 日期非法: *this endl;}
}// 流提取 写
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;
} 二 . 取地址运算符重载
2.1 const 成员函数 将const 修饰的成员函数称之为 const 成员函数 const 修饰成员函数放在成员函数参数后面 。const 实际修饰 该成员函数隐含的 this 指针 表明在该成员函数中不能对类的任何成员进行修改 。 const 修饰Date 类的 Print成员函数 Print 隐含的 this指针由 Date* const this 变为 Date* const this 2.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; // ⽇
};
另 : 不要过分相信编译器的红色波浪线的报错 一切以编译的结果为准 因为编译器在这里进行的只是预检查 可能具有滞后性 或者一些BUG
总代码
Date.cpp
#include Date.hbool Date::CheckDate()
{if (_month 1 || _month 12|| _day 1 || _day GetMonthDay(_year, _month)){return false;}else{return true;}
}Date::Date(int year, int month, int day)
{_year year;_month month;_day day;if (!CheckDate()){cout 日期非法: *this endl;}
}Date* Date::operator()
{return this;// return nullptr;
}
const Date* Date::operator()const
{return this;// return nullptr;
}void Date::Print()const
{cout _year / _month / _dayendl;
}bool Date::operator(const Date d) const
{if (_year d._year){return true;}else if(_year d._year_month d._month){return true;}else if(_year d._year _month d._month){return _day d._day;}return false;
}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);
}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){_month 1;_year;}}return *this;
}//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._month 1;
// tmp._year;
// }
// }
// return tmp;
//}// 复用实现
//Date Date::operator(int day)
//{
// *this *this _day;
// return *this;
//}// 复用实现
Date Date::operator(int day) const
{Date tmp(*this);tmp day;return tmp;
}Date Date::operator-(int day)
{if (day 0)return *this (-day);_day - day;while (_day0){//借位--_month;if (_month 0){--_year;_month 12;}_day GetMonthDay(_year, _month);}return *this;
}Date Date::operator-(int day) const
{Date tmp(*this);tmp._day - day;return tmp;
}//前置
Date Date::operator()
{*this *this 1;return *this;
}
//后置
Date Date::operator(int)
{Date tmp *this;*this *this 1;return tmp;
}//前置--
Date Date::operator--()
{*this *this - 1;return *this;
}
//后置--
Date Date::operator--(int)
{Date tmp *this;*this *this - 1;return tmp;
}//d1 - d2
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 flag * n;
}// 流插入 读
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()){break;}else{cout 输入的日期非法请重新输入:endl;}}return in;
}
Date.h
#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 1, int month 1, int day 1);void Print()const;//Date* operator();const Date* operator()const;bool CheckDate();int GetMonthDay(int year, int month){static int monthDayArry[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;}return monthDayArry[month];}//运算符重载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)const;Date operator(int day);//d1 - 天数Date operator-(int day)const;Date operator-(int day);//前置 / 后置 //前置Date operator();//后置Date operator(int);//前置 / 后置 --//前置--Date operator--();//后置--Date operator--(int);//d1 - d2int operator-(const Date d) const;private:int _year;int _month;int _day;
};// 流插入
ostream operator(ostream out, const Date d);// 流提取
istream operator(istream in,Date d);
Test.cpp
#include Date.hvoid Test1()
{// Date d1(2024, 11, 22);Date d2(2024, 11, 1);Date d3(d1);d1.Print();d2.Print();d3.Print();cout (d2 d1) endl;cout (d2 d3) endl;cout (d2 d1) endl;cout (d2 d1) endl;cout (d1 d3) endl;cout (d1 ! d3) endl;}void Test2()
{// / //Date d1(2024, 11, 1);//Date d2 d1 50;//Date d3 d1 50;//d1.Print();//d2.Print();//d3.Print();//d1.Print();//Date d1(2024, 11, 22);//Date d2 d1 -50;//d1.Print();//d2.Print();Date d3(2024, 11, 22);//Date d4 d3--;//Date d5 --d3;//d4.Print();//d5.Print();//d3.Print();cout d3;}void Test3()
{Date d1(2024, 11, 22);Date d2(2024, 11, 1);cout d1 d2 d1;cin d1 d2;
}void Test4()
{Date d1(2024, 2, 29);Date d2(2023, 2, 29);cin d1 d2;cout d1 d2;
}void Test5()
{const Date d1(2024, 2, 29);Date d2(2023, 2, 29);
}
int main()
{//Test1();//Test2();//Test3();Test4();return 0;
}