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

高级设计网站建站系统

高级设计网站,建站系统,北京造价信息网官网,意派h5制作平台官网1 运算符重载 运算符重载是一种特殊的函数,通过operator关键字定义,让自定义类型支持标准运算符: Vector operator(const Vector& v1, const Vector& v2) {return Vector(v1.x v2.x, v1.y v2.y); } 基本语法规则: 返…

1 运算符重载

运算符重载是一种特殊的函数,通过operator关键字定义,让自定义类型支持标准运算符:

Vector operator+(const Vector& v1, const Vector& v2) {return Vector(v1.x + v2.x, v1.y + v2.y);
}

基本语法规则:

返回类型 operator运算符符号(参数列表) {// 实现逻辑
}

参数是操作符的操作个数,如:比较大小使用双操作符,解引用、取地址、++、--使用单操作符。

eg:判断是否相等

class Date
{
public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}int GetYear(){return _year;}//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;
}int main()
{Date d3(2024, 4, 14);Date d4(2024, 4, 14);// 显式调用operator==(d3, d4);if (d3 == d4)// 直接写,转换调用,编译会转换成operator==(d3, d4);{cout << "相等" << endl;}else{cout << "不相等" << endl;}return 0;
}

在上述函数中,将运算符重载成全局,为了访问私有成员,将private改为public,对程序的封装性不友好。

解决方案:
1、提供这些成员get和set
2、友元
3、重载为成员函数(一般使用这种)

以重载为成员函数为例:

class Date
{
private:int _year;int _month;int _day;
public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}//bool operator==(Date* this, const Date& d),成员函数都隐藏this,指向调用函数的对象bool operator==(const Date& d){return this->_year == d._year&& this->_month == d._month&& this->_day == d._day;}
};
int main()
{Date d3(2024, 4, 14);Date d4(2024, 4, 14);// 显式调用d3.operator==(d4);//==》bool operator==(Date* d3,const Date& d4)// 直接写,装换调用,编译会转换成operator==(d3, d4);if (d3 == d4){cout << "相等" << endl;}else{cout << "不相等" << endl;}return 0;
}

注意:由于成员函数中都存在一个指向调用函数的对象的this,所以在重载为成员函数时,应从bool operator==(Date& d1, const Date& d2) 变为bool operator==(Date* this, const Date& d)==>z`bool operator==(const Date& d)

1.1 运算符重载原则

不能创建新运算符:只能重载C++已有的运算符,即函数名必须是C/C++中有的。

// 非法:operator@ 不存在

至少一个类类型操作数

// 合法:操作数包含自定义类型
Vector operator+(const Vector&, const Vector&);// 非法:两个内置类型
int operator+(int, int); 

不能改变运算符的原始语义:用于内置类型的运算符,其含义不能改变,例如:内置的整形+不能改变其含义。

不可重载的运算符.*(成员指针访问)、::(作用域解析)、?:(三元条件)sizeof、.(成员访问)。

成员指针访问不常见,这里举一个例子。

class OB
{
public:void func(){cout << "void func()" << endl;}
};typedef void(OB::* PtrFunc)();//将PtrFunc设置为成员函数指针类型int main()
{//普通函数使用函数名就是地址,成员函数规定要加&PtrFunc ptr = &OB::func;//OB temp;(temp.*ptr)();//使用.*解引用func函数return 0;
}

2 赋值运算符重载

赋值运算符(=)用于将已有对象的值复制给另一个已存在的对象。与拷贝构造函数不同,它作用于已初始化的对象。

  • 拷贝构造:一个已经存在的对象,拷贝给另一个创建同时初始化的对象。
  • 赋值:针对两个已经存在的对象class A和classB,,将A赋值给B或将B赋值给A。
Date d1(2023, 1, 1);
Date d2(2024, 2, 2);
d1 = d2;  // ,d1和d2在前两行已经存在,调用赋值运算符
Date d3(d1);//d3在这行刚刚创建,用d1初始化d3,调用拷贝构造

当用户没有显式实现时,编译器会生成一个默认赋值运算符重载,内置类型成员变量直接赋值,自定义类型需调用对应类的赋值运算符完成赋值。

2.1赋值运算符重载格式

class Date {
public:// 赋值运算符重载Date& operator=(const Date& other) {if(this != &other) {  // 防止自赋值_year = other._year;_month = other._month;_day = other._day;}return *this;  // 支持链式赋值}
};

关键设计要素:

  • 返回类型Date&(支持连续赋值 a = b = c),若返回值为Date,return *this会生成一个当前对象的临时拷贝作为当前函数返回值,自定义类型需要调用拷贝构造,使用Date&引用返回,返回一个别名,不需要拷贝构造,提高了运行效率。

  • 参数类型const Date&,传递引用可以提高传参效率,避免拷贝,同时保护原对象。
  • 自赋值检查if(this != &other),防止自己给自己复制,浪费计算资源。
  • 返回当前对象return *this,规定返回左操作数,即调用函数的类==》隐藏的*this
class Date
{
public:Date(int year = 1900, 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;}//赋值拷贝// d2=this,d3=d;Date& 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;}~Date()//析构函数{//清楚观察调用析构函数cout << "~Date()" << endl;_year = -1;_month = -1;_day = -1;}private:int _year;int _month;int _day;
};
int main()
{Date d2(2025, 6, 18);d2.Print();Date d3(2026, 7, 20);d2 = d3;d2.Print();d3.Print();
}

        上述程序中,若赋值函数为void operator=(const Date& d)完成d2=d3赋值操作(此时应删去return *this),具体表现为d2.Print和d3.Print输出结果相同。但由于d2=d3==》d2.operator(d3)=》d2调用operator函数完成赋值后返回值为void,此时如果想继续赋值即d1=d2=d3会发生报错。具体如下:

        对于int i,j,k. i =j=k=1连续赋值,1作为右操作数赋值给k,返回值为int k,k作为右操作数赋值给j,返回值为int j,j作为右操作数赋值给i,返回值为int i。在这之中,若函数的返回值为void,则会发生报错:“没有找到接受void类型的右操作数的运算符”。所以为支持连续赋值,函数的参数类型、返回值类型应保持一致。

函数返回值总结:

  • 返回对象是一个局部对象或者临时对象,出当前函数作用域就析构销毁了,就不能使用引用返回,如果使用引用返回,引用对象在func函数栈上就已经销毁了,导致野引用。
  • 虽然引用返回可以减少一次拷贝情况,但必须是出了函数作用域后返回对象还在,才能使用引用返回。
  • 赋值重载应注意:返回值要支持连续赋值并且用引用返回,同时判断一下是否是自己给自己赋值

2.2 赋值运算符显示实现

  • 赋值运算符只能重载成类的成员函数,不能重载成全局函数。
class Date
{
public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}int _year;int _month;int _day;
};Date& operator=(Date& left, const Date& right)
{if (&left != &right){left._year = right._year;left._month = right._month;left._day = right._day;}return left;
}

在上述程序中,赋值运算符如果不能显式实现,编译器会生成一个默认的,此时用户在类外自己生成一个全局赋值运算符重载,就和编译器在类中生成的冲突了,故赋值运算符只能重载是类的成员函数。

  • 用户没有显示实现赋值运算符时,编译器会生成一个默认赋值运算符,并以字节方式逐渐拷贝。内置类型成员变量直接赋值,自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值,与拷贝构造类似。

3 利用运算符重载实现日期类 

头文件

#pragma once
#include<iostream>
using namespace std;#include<assert.h>class Date
{
private:int _year;int _month;int _day;//友元函数声明,使operator可以调用Date中的private数据friend ostream& operator<<(ostream& out, const Date& d);friend istream& operator>>(istream& in, Date& d);//友元
public:Date(int year = 1900, int month = 1, int day = 1);//缺省参数尽量在声明时候给void Print() const;// 直接定义类里面,他默认是inline// 频繁调用int GetMonthDay(int year, int month){assert(month > 0 && month < 13);static int monthDayArray[13] = { -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };// 365天 5h +if (month == 2 && (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)){return 29;}else{return monthDayArray[month];}}bool CheckDate();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 + 100Date& operator+=(int day);Date operator+(int day) const;Date& operator-=(int day);//++d前置++Date& operator++();//d++后置++Date operator++(int);//增加一个int形参,构成函数重载//前置--Date& operator--();//后置--Date operator--(int);int operator-(const Date& d)const;};

其中

  • Date& operator++();属于前置++,为了与后置++区分构成函数重载,强行增加一个Int(不需要写形参名,接受值是多少不重要,也不用,仅仅是为了跟前置++区分开)。
  • friend ostream& operator<<(ostream& out, const Date& d);和friend istream& operator>>(istream& in, Date& d);是在类外实现的,在类内构成Date类的友元函数,可以访问类内的私有元素。
  • bool operator<(const Date& d) const;中的const是为了修视成员函数中隐藏的this指针,表明在该成员函数中不能对类的任何成员进行修改。

具体实现

#define _CRT_SECURE_NO_WARNINGS 1
#include "Date.h"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 << "日期非法" << endl;} 
}void Date::Print() const//声明和定义分离要制定类域,定义声明中类的函数:返回值类型 类名::函数名()
{cout << _year << "-" << _month << "-" << _day << endl;
}bool Date::operator<(const Date& d) const
{if (this->_year < d._year){return true;}else if (this->_year == d._year){if (this->_month < d._month){return true;}else if (this->_month == d._month){return this->_day < d._day;}}return false;
}
bool Date::operator<=(const Date& d) const
{if (*this > d){return false;}else{return true;}
}bool Date::operator==(const Date& d) const
{return this->_year == d._year&& this->_month == d._month&& this->_day == d._day;
}bool Date::operator>(const Date& d) const
{if (*this < d || *this == d){return false;}else{return true;}
}bool Date::operator>=(const Date& d) const
{if (*this < d){return false;}else{return true;}
}bool Date::operator!=(const Date& d) const
{if (*this == d){return false;}else{return true;}
}Date& Date::operator+=(int day)
{if (day < 0){day = -day;return (*this).operator-=(day);}_day = _day + day;while(_day > GetMonthDay(_year, _month))//大于当前月天数,要进月{//说明现在的天数和大于当前月的最大天数,//天数-本月最大天数,月进位_day = _day - GetMonthDay(_year, _month);//减去当前月的天数_month++;//月份进1;类似十进制加法。11+10=1*10+1+10 = 1*10+11==2*10 +(11-10);if (_month > 12){_month = 1;_year++;}}return *this;
}Date Date::operator+(int day) const
{Date tmp = *this;tmp += day;return tmp;
}Date& Date::operator-=(int day)
{if (day < 0){day = -day;return (*this).operator+=(day);}_day = _day - day;//借当前月份的天数while (_day <= 0){//说明当前月份天数借完了,开始借上个月天数,借位_month--;if (_month == 0){_month = 12;_year--;}	_day = _day + GetMonthDay(_year, _month);}return *this;
}//前置++
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;
}
Date Date::operator--(int)
{Date tmp(*this);*this -= 1;return tmp;
}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;
}ostream& operator<<(ostream& out, const Date& d)
{out << d._year << "年"s << d._month << "月" << d._day << "日" << endl;return out;
}istream& operator>>(istream& in, Date& d)
{cout << "请依次输入年、月、日" << endl;in >> d._year >> d._month >> d._day;if (!d.CheckDate()){cout << "日期非法" << endl;}return in;
}

http://www.dinnco.com/news/26785.html

相关文章:

  • 佛山公司建站青岛seo推广专员
  • 做网站项目的流程seo关键词布局
  • 大型大型网站建设方案站长之家app
  • 台州市建设工程造价管理处网站个人网站制作模板主页
  • 个人创建网站程序seo软文推广
  • 网站制作论文总结今日的最新消息
  • 青海省网站建设哪家公司比较靠谱爱站网反链查询
  • 山东省城乡和住房建设厅网站seo快速排名软件价格
  • 广州十大网站建设信息流优化师培训
  • 辽宁建设局网站首页最新引流推广方法
  • 华为网站哪个公司做的seo实战教程
  • 中投建设官方网站免费做网站的平台
  • seo中国官网免费网站排名优化在线
  • nodejs做静态网站纵横seo
  • 网站建设员岗位职责网络营销的营销方式
  • 怎么做网站赚流量广告联盟全自动赚钱系统
  • 对中国建设银行网站的优点百度关键词搜索排名多少钱
  • 黑龙江做网站找谁全网营销型网站
  • 一个公司可以有两个网站吗seo查询seo优化
  • 赤峰市建设厅官方网站厦门关键词优化企业
  • 武汉市汉阳区建设局网站电子商务网站开发
  • 如何看网站日志点金推广优化公司
  • 虚拟主机网站建设过程网络服务器是指什么
  • 莱芜 做网站 公司电商网站seo优化
  • 手机网站轮播图东莞网站seo技术
  • 网页设计工作室seo是什么牌子
  • wordpress简约博客主题成都最好的网站推广优化公司
  • 小学生做电子小报的网站黄冈网站seo
  • cdn网络对网站开发有影响吗西安优化排名推广
  • eclipse可以做门户网站嘛网络营销的种类有哪些