备份核验单时网站域名WordPress微博图片
- 作者: 五速梦信息网
- 时间: 2026年03月21日 10:06
当前位置: 首页 > news >正文
备份核验单时网站域名,WordPress微博图片,定制网站建设公司有哪些,网站页面布局图文章目录 前言一、赋值运算符重载运算符重载赋值运算符重载赋值运算符不可重载为全局函数前置和后置的重载 二、const修饰成员函数三、取地址及const取地址操作符重载四、日期类的实现构造函数日期 天数日期 天数日期 - 天数日期 - 天数日期类的大小比较日期类 日期类日… 文章目录 前言一、赋值运算符重载运算符重载赋值运算符重载赋值运算符不可重载为全局函数前置和后置的重载 二、const修饰成员函数三、取地址及const取地址操作符重载四、日期类的实现构造函数日期 天数日期 天数日期 - 天数日期 - 天数日期类的大小比较日期类 日期类日期类 日期类日期类 日期类日期类 日期类日期类 日期类日期类 ! 日期类 日期类 - 日期类 五、流插入流提取运算符重载总结 前言 继承上节的内容本节内容依旧量大管饱 一、赋值运算符重载
运算符重载 C为了增强代码的可读性引入了运算符重载运算符重载是具有特殊函数名的函数其目的就是让自定义类型可以像内置类型一样可以直接使用运算符进行操作。 请记住这个目的我们的接下来的一切都是围绕这个来展开 运算符重载函数也具有自己的返回值类型函数名字以及参数列表。其返回值类型和参数列表与普通函数类似。 运算符重载函数名为关键字operator后面接需要重载的操作符符号。
注意
不能通过连接其他符号来创建新的操作符比如operator。(需要是C/C语法中存在)重载操作符必须有一个类类型或枚举类型的操作数。(不能去重载运算符改变内置类型的行为) - 其实要真那么搞也可以但是很无聊没什么实用的用于内置类型的操作符重载后其含义不能改变。- 例如内置的整型不能改变其含义作为类成员的重载函数时函数有一个默认的形参this限定为第一个形参。sizeof 、:: 、.* 、?: 、. 这5个运算符不能重载。并不是运算符都是需要重载的需要看是否有存在的意义参数部分需要对应顺序
// 来个实际例子
class Date
{
public:Date(int year 0, int month 1, int day 1){_year year;_month month;_day day;}void Print(){cout _year 年 _month 月 _day 日 endl;}// 注意此时该函数的第一个形参默认为this指针bool operator(const Date d)// 运算符重载函数{return _year d._year_month d._month_day d._day;}
private:int _year;int _month;int _day;
};int main()
{Date d1(2024, 9, 22);Date d2 d1;// 注意优先级cout (d1 d2) endl; // 1cout d1.operator(d2) endl; // 与上一条语句等价return 0;
}显然第一种 d1 d2 这种形式相当明了就好像Date真的是我们的内置类型一样其实说白了还是编译器帮我们化成了第二种形式不信我们可以看下汇编形式 还是那句话当你觉得轻松的时候总是有人为你负重前行 赋值运算符重载 先上代码
class Date
{
public:Date(int year 0, int month 1, int day 1) // 构造函数{_year year;_month month;_day day;}Date operator(const Date d) // 赋值运算符重载函数{if (this ! d) // 防止会有 d1 d1 这样自己赋值给自己{_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;
};我们要注意以下几点
参数类型设置为引用并用const进行修饰 - 由于是自定义类型传参我们若是使用传值传参会额外调用一次拷贝构造函数所以函数的第二个参数最好使用引用传参第一个参数是默认的this指针我们管不了。并且我们也不改变它那就用 const 来修饰函数的返回值使用引用返回 - 本质上是为了支持连续赋值所以必须要有个返回值而且很显然是返回左操作数 d3 d2 d1; 所以我们在这里返回 this 指针且因为此时出了函数作用域this指针指向的对象并没有被销毁所以可以使用引用返回又省了拷贝多余的资源消耗一个类如果没有显示定义赋值运算符重载编译器也会自动生成一个完成对象按字节序的值拷贝 - 没错赋值运算符重载编译器也可以自动生成并且也是支持连续赋值的。但是编译器自动生成的赋值运算符重载完成的是对象按字节序的值拷贝例如d2 d1编译器会将d1所占内存空间的值完完全全地拷贝到d2的内存空间中去类似于memcpy
// 请注意区分
Date d1(2024,9,22);
Date d2 d1; // 拷贝构造
Date d3;
d3 d1; // 赋值// 拷贝构造函数用一个已经存在的对象去构造初始化另一个即将创建的对象
// 赋值运算符重载函数在两个对象都已经存在的情况下将一个对象赋值给另一个对象赋值运算符不可重载为全局函数 赋值运算符重载跟拷贝构造类似如果不显式实现编译器会生成一个默认的赋值运算符重载此时用户再类外自己实现一个全局的赋值运算符重载就和编译器在类中生成的默认赋值运算符重载冲突故而赋值运算符只能是类的成员函数(其他运算符函数可以重载为全局函数) 《C Primer》第5版P500有言 默认生成赋值运算符重载对于内置类型与自定义类型处理方式
内置类型成员变量直接赋值的自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值 同样的我们有个深拷贝和浅拷贝的问题方式还是跟拷贝构造方式一样当涉及到动态资源申请的时候深拷贝否则浅拷贝即可
前置和后置的重载 这两个妙就妙在一样就只有一个操作符一个操作符在前一个在后
C给出了它的解决方案
//d1
Date operator()
{_day 1;return *this;
}//d1
Date operator(int)
{Date temp(this);_day 1;return temp;
}请注意后置重载函数中的参数int没有实际作用只是为了与前置构成函数重载以便区分 二、const修饰成员函数 将const修饰的 “成员函数” 称之为 const 成员函数const修饰类成员函数实际修饰改成员隐含的 this 指针表明在该成员函数中不能对类的任何成员进行修改如图 在讲解具体的实用场景前我们还可以先来看看这四个问题答案和解释我都会相应给出
const对象可以调用非const成员函数吗非const对象可以调用const成员函数吗const成员函数内可以调用其他的非const成员函数吗非const成员函数内可以调用其他的const成员函数吗 答案是不可以、可以、不可以、可以 解释 5. 非const成员函数即成员函数的this指针没有被const所修饰我们传入一个被const修饰的对象用没有被const修饰的this指针进行接收属于权限的放大函数调用失败 6. const成员函数即成员函数的this指针被const所修饰我们传入一个没有被const修饰的对象用被const修饰的this指针进行接收属于权限的缩小函数调用成功 7. 在一个被const所修饰的成员函数中调用其他没有被const所修饰的成员函数也就是将一个被const修饰的this指针的值赋值给一个没有被const修饰的this指针属于权限的放大函数调用失败 8. 在一个没有被const所修饰的成员函数中调用其他被const所修饰的成员函数也就是将一个没有被const修饰的this指针的值赋值给一个被const修饰的this指针属于权限的缩小函数调用成功 权限可以平移也可以缩小但是不可以放大 好我们接下来来看以下代码
// Print()成员函数没有被const修饰
int main()
{Date d1(2024, 9, 22);d1.Print(); // right权限平移const Date d2(2024, 9, 22);d2.Print(); // err权限放大return 0;
}但是并非所有函数都需要加上 const 修饰的如果对成员变量进行读写访问的函数不能加上 const 另外const修饰成员函数是修饰this指针的那么 流插入 与 流提取 不是在类中实现没有隐含的this指针不能使用 const 修饰
三、取地址及const取地址操作符重载 这两个默认成员函数一般不用重新定义编译器会默认生成的无需你多虑
class Date
{
public:Date operator(){return this;}const Date* operator() const{return this;}
private:int _year; int _month; int _day;
};四、日期类的实现 学完了这6个默认成员函数我们来写个日期类巩固一下吧
class Date
{
public:// 构造函数Date(int year 1900, int month 1, int day 1);// 打印函数void Print() const;// 日期天数Date operator(int day);// 日期天数Date operator(int day) const;// 日期-天数Date operator-(int day);// 日期-天数Date operator-(int day) const;// 前置Date operator();// 后置Date operator(int);// 前置–Date operator–();// 后置–Date operator–(int);// 日期的大小关系比较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;// 日期-日期int operator-(const Date d) const;// 析构拷贝构造赋值重载可以不写使用默认生成的即可private:int _year;int _month;int _day;
};构造函数
// 获取某年某月的天数
inline int GetMonthDay(int year, int month)
{// 数组存储平年每个月的天数static int dayArray[13] { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };int day dayArray[month];if (month 2 ((year % 4 0 year % 100 ! 0) || (year % 400 0))){//闰年2月的天数day 29;}return day;
}
// 构造函数
Date::Date(int year, int month, int day)
{// 检查日期的合法性if (year 0 month 1 month 12 day 1 day GetMonthDay(year, month)){_year year;_month month;_day day;}else{// 严格来说抛异常更好cout 非法日期 endl;cout year 年 month 月 day 日 endl;}
}其中我们注意一下这个GetMonthDay函数
该函数可能被多次调用所以我们最好将其设置为内联函数函数中存储每月天数的数组最好是用static修饰存储在静态区避免每次调用该函数都需要重新开辟数组逻辑与应该先判断 month 2 是否为真因为当不是2月的时候我们不必判断是不是闰年短路判断
日期 天数 因为出了作用域对象还存在于是我们用引用返回 逻辑如下 1.若日已满则日减去当前月的天数月加一。 2.若月已满则将年加一月置为1
// 日期 天数
Date Date::operator(int day)
{if (day0){// 复用operator-*this - -day;}else{_day day;// 日期不合法通过不断调整直到最后日期合法为止while (_day GetMonthDay(_year, _month)){_day - GetMonthDay(_year, _month);_month;if (_month 12){_year;_month 1;}}}return *this;
}日期 天数 因为返回对象的值不变但我们要返回变化后的值于是就可以通过复用、创建临时变量tmp来解决因为tmp出了作用域就销毁于是我们用传值返回
// 日期 天数
Date Date::operator(int day) const
{Date tmp(*this);// 拷贝构造tmp用于返回// 复用operatortmp day;return tmp;
}日期 - 天数
逻辑如下 1.若日为负数则月减一。 2.若月为0则年减一月置为12。 3.日加上当前月的天数
// 日期 - 天数
Date Date::operator-(int day)
{if (day 0){// 复用operator*this -day;}else{_day - day;// 日期不合法通过不断调整直到最后日期合法为止while (_day 0){_month–;if (_month 0){_year–;_month 12;}_day GetMonthDay(_year, _month);}}return *this;
}日期 - 天数 跟日期 天数类似也是复用
// 日期-天数
Date Date::operator-(int day) const
{Date tmp(*this);// 拷贝构造tmp用于返回// 复用operator-tmp - day;return tmp;
}日期类的大小比较 这里我们将充分发挥复用的智慧
日期类 日期类
逻辑年大则大月大则大年月相等比日
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 _year d._year_month d._month_day d._day;
}日期类 日期类
逻辑复用前面两个
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 !(*this d);
}日期类 - 日期类 其实也就是算两个日期之差它还是有点意义的 试想一下假如你未来结婚结婚到一半新娘子问你我们几年几月几日遇见的 你早有准备一下就回答上来 突然新娘子还不死心问你遇见当天离今天一共经历多少天 你就可以说“不急我先跑个程序” 这就是日期类 - 日期类的一个实际场景运用 有两种思路请听我细细道来 方法一所谓日期 - 日期即计算传入的两个日期相差的天数。我们只需要让较小的日期的天数一直加一直到最后和较大的日期相等即可这个过程中较小日期所加的总天数便是这两个日期之间差值的绝对值。若是第一个日期大于第二个日期则返回这个差值的正值若第一个日期小于第二个日期则返回这个差值的负值这很容易设置一个判别变量 flag 即可
// 日期-日期
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;
}方法二所谓“年、月、日”不过也是一种进位的方式那我们可以全把数堆给“日”这个位先将年等同再将月等同最后直接将两个日期的“日”位相减即可只需要注意返回的是正值还是负值
int Date::operator-(const Date d)
{Date greD (*this) d ? *this : d;Date smlD (*this) d ? *this : d;while (greD._year smlD._year) {if (isLeapYear(greD._year - 1)) greD._day 366;else greD._day 365;greD._year - 1;}while (greD._month smlD._month) {greD._month - 1;greD._day GetMonthDay(greD._year, greD._month);}while (greD._month smlD._month) {greD._month 1;greD._day - GetMonthDay(greD._year, greD._month);}int ret greD._day - smlD._day;return *this d ? ret : -ret;
}五、流插入流提取运算符重载 这个比较困难有一些不懂的概念可以暂且放一下 其实我们平时说cout、cin能自动识别类型本质上就是因为重载cout属于ostream类cin属于istream类 假如我们 重载运算符 为成员函数隐含的 this 指针占用第一个参数的位置Date必须是左操作数使用时候d1cout 是不符合我们的习惯的 于是我们要将其重载为全局函数并且把ostream out放在第一个位置但是又引出了另一个问题:类外不能访问类中的私有成员如果将私有权限放开就缺乏安全性对此C中有友元接下来我们会涉及到这里就使用下虽然这个全局函数不在类中但是可以访问私有成员函数
//友元告诉该类这两个全局函数是我们的朋友允许使用私有成员(在类中)friend ostream operator(ostream out, const Date d);friend istream operator(istream in, Date d);ostream operator(ostream out, const Date d)
{out d._year d._month d._day endl;return out;
}istream operator(istream in, Date d)
{in d._year d._month d._day;return in;
}总结 哈哈这个中篇终于结束了想不到吧学Cpp的第一个大内容就如此困难 还有个下篇呢继续加油吧
- 上一篇: 备案主体负责人 网站负责人源码出售平台
- 下一篇: 背景色搭配网站网站上传图片加水印
相关文章
-
备案主体负责人 网站负责人源码出售平台
备案主体负责人 网站负责人源码出售平台
- 技术栈
- 2026年03月21日
-
备案增加网站网页设计原则
备案增加网站网页设计原则
- 技术栈
- 2026年03月21日
-
备案怎么关闭网站网站开发 php 书籍 推荐
备案怎么关闭网站网站开发 php 书籍 推荐
- 技术栈
- 2026年03月21日
-
背景色搭配网站网站上传图片加水印
背景色搭配网站网站上传图片加水印
- 技术栈
- 2026年03月21日
-
背景色搭配网站网站外链建设分析
背景色搭配网站网站外链建设分析
- 技术栈
- 2026年03月21日
-
背投广告典型网站网站推广公司 wordpress
背投广告典型网站网站推广公司 wordpress
- 技术栈
- 2026年03月21日






