做招聘信息的网站有哪些内容,上传网站程序,ui设计个人作品集,网站开发对数据库的要求前文#xff1a;
c阶梯之类与对象#xff08;上#xff09;-CSDN博客
c阶梯之类与对象#xff08;中#xff09;-CSDN博客 前言#xff1a; 在上文中#xff0c;我们学习了类的六个默认成员函数之构造#xff0c;析构与拷贝构造函数#xff0c;接下来我们来看看剩下…前文
c阶梯之类与对象上-CSDN博客
c阶梯之类与对象中-CSDN博客 前言 在上文中我们学习了类的六个默认成员函数之构造析构与拷贝构造函数接下来我们来看看剩下的默认成员函数。 目录
前文
前言
5. 赋值运算符重载
5.1 运算符重载
普通函数版
运算符重载版 5. 2 赋值运算符重载
1. 赋值运算符重载格式 2. 实例
注意 5.3 特殊的运算符重载 前置与后置 6. Date类的实现多功能
Date.h
Date.cpp
main.cpp
补充知识
7.const成员
8. 取地址及const取地址操作符重载 5. 赋值运算符重载
5.1 运算符重载
我们知道函数重载那么运算符重载又是什么 C为了增强代码的可读性引入了运算符重载运算符重载是具有特殊函数名的函数也具有其 返回值类型函数名字以及参数列表其返回值类型与参数列表与普通的函数类似。 函数名字为关键字operator后面接需要重载的运算符符号。 函数原型返回值类型 operator操作符(参数列表)注意 不能通过连接其他符号来创建新的操作符比如operator 重载操作符必须有一个类类型参数 用于内置类型的运算符其含义不能改变例如内置的整型不 能改变其含义 作为类成员函数重载时其形参看起来比操作数数目少1因为成员函数的第一个参数为隐藏的this .* :: sizeof ?: . 注意以上5个运算符不能重载。这个经常在笔试选择题中出 现 我们可以这样认为运算符重载就是给运算符赋予一个新的含义专为自定义类型而生 不过默认并不会改变运算符的基本逻辑。
我们来看看他在实际中的应用我们实现两个Date类对象比较1.是否相等 2. 是否小于
普通函数版
我们可以看到在这个版本里代码编写者取名十分随意那么当别人看到这段代码内心的活动估计十分激昂。虽然在功能上很完美但其代码却会让人抓耳挠腮。
class Date
{
public:Date(int year 2024, int month 2, int day 6){_year year;_month month;_day day;}//Data类拷贝构造赋值重载析构都不需要自己实现bool compare1(const Date d) //DateEqual {return _year d._year _month d._month _day d._day;}bool compare2(const Date d)//DateLess{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;}private:int _year;int _month;int _day;
};
int main()
{Date d1(2024, 2, 7);Date d2(1997, 1, 1);cout d1.compare1(d2) endl;cout d1.compare2(d2) endl;return 0;
}
运算符重载版
这一版本的代码可读性大大增强还免去了起名的麻烦同时在调用函数的时候自定义类型也可以像内置类型一样简单快捷的使用运算符。
class Date
{
public:Date(int year 2024, int month 2, int day 6){_year year;_month month;_day day;}//Data类拷贝构造赋值重载析构都不需要自己实现bool operator(const Date d){return _year d._year _month d._month _day d._day;}bool operator(const Date d){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;}private:int _year;int _month;int _day;
};
int main()
{Date d1(2024, 2, 7);Date d2(1997, 1, 1);return 0;
}int main()
{Date d1(2024, 2, 7);Date d2(1997, 1, 1);/*cout d1.operator(d2) endl;cout d1.operator(d2) endl;*/cout (d1 d2) endl;//在编译器看来等同于cout d1.operator(d2) endl;cout (d1 d2) endl;//在编译器看来等同于cout d1.operator(d2) endl;return 0;
} 注意因为 的运算符很高因此在调用时需要加括号。 运算符重载并不会改变运算符的底层逻辑因此对于双操作数运算符来说左操作数就是函数的第一个参数右操作数是第二个参数。 那么运算符重载能定义成全局的吗是的可以但是这样我们就不能访问类的私有成员。但将类成员公有化如何保证封装性呢 我们可以使用友元函数或者定义成成员函数。 5. 2 赋值运算符重载
1. 赋值运算符重载格式 参数类型const T传递引用可以提高传参效率 返回值类型T返回引用可以提高返回的效率有返回值目的是为了支持连续赋值 检测是否自己给自己赋值 返回*this 要复合连续赋值的含义 2. 实例 我们发现所谓的赋值重载与之前学到的拷贝构造几乎是一个模子里刻出来的既然他们一样那我们还有必要学他吗 这里有一个误区他们的实现确实一样但有一个不同点。 拷贝构造是对并不存在的对象进行拷贝构造既有拷贝又有构造 赋值重载是对已经存在的对象进行赋值拷贝。 class Date
{
public:Date(int year 2024, int month 2, int day 6){_year year;_month month;_day day;}Date(Date d){_year d._year;_month d._month;_day d._day;}bool operator(const Date d){return _year d._year _month d._month _day d._day;}bool operator(const Date d){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 operator!(const Date d){return !(*this d);}Date operator(const Date d){if (*this ! d){_year d._year;_month d._month;_day d._day;}return *this;}private:int _year;int _month;int _day;
};int main()
{Date d1(2024, 2, 7);Date d2(1997, 1, 1);int a 10;int b 20;Date d3 d1;//拷贝构造即Date d3(d1);Date d4;d4 d1;//赋值重载return 0;
}
我们在汇编视角可以看的更加清晰。 注意 赋值重载只能定义成类的成员函数不能定义成全局函数。 编译器不支持定义为全局函数如果定义成全局会报错。 定义成全局函数那么类中没有实现作为默认成员函数之一编译器会自动生成一个默认赋值重载那么当调用的时候就会产生冲突。 用户没有显式实现时编译器会生成一个默认赋值运算符重载以值的方式逐字节拷贝。注意内置类型成员变量是直接赋值的而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。 我们不写编译器会自动生成那么我们还需要写吗 视情况而定值拷贝对于Date类来说很适用那么对于我们之前写的Stack类呢他会造成不小的麻烦 。关于这一点在c阶梯之类与对象中-CSDN博客中的拷贝构造函数一节有详细讲解感兴趣的宝子可以去看看。 5.3 特殊的运算符重载 前置与后置 前置和后置都是一元运算符为了让前置与后置形成能正确重载 C规定后置重载时多增加一个int类型的参数但调用函数时该参数不用传递编译器 自动传递 Date operator(int)//后置后置使用后加1因此返回的结果是自己本身返回之后自身1
{Date tmp *this;_day1;return tmp;
}Date operator()//前置前置使用前前置返回的结果是自身1
{_day;return *this;
} 6. Date类的实现多功能
在Date类实现常用运算符的重载日期计算器两日期的间隔等功能。
Date.h #includeiostream
using namespace std;
class Date
{
public:// 获取某年某月的天数int GetMonthDay(int year, int month);// 全缺省的构造函数Date(int year , int month , int day );// 拷贝构造函数Date(const Date d);// 赋值运算符重载Date operator(const Date d);// 析构函数~Date();// 日期天数Date operator(int day);// 日期天数Date operator(int day);// 日期-天数Date operator-(int day);// 日期-天数Date operator-(int day);// 前置Date operator();// 后置Date operator(int);// 后置--Date operator--(int);// 前置--Date operator--();// 运算符重载bool operator(const Date d);// 运算符重载bool operator(const Date d);// 运算符重载bool operator (const Date d);// 运算符重载bool operator (const Date d);// 运算符重载bool operator (const Date d);// !运算符重载bool operator ! (const Date d);// 日期-日期 返回天数int operator-(const Date d);//打印void Print();private:int _year;int _month;int _day;};
Date.cpp
#includeDate.h
//获取每个月的天数
int Date::GetMonthDay(int year, int month)
{int monthDays[13] { 0,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 monthDays[month];
}
//全缺省构造函数
Date::Date(int year 1997, int month 1, int day 1)
{_year year;_month month;_day day;
}//拷贝构造
Date::Date(const Date d)
{_year d._year;_month d._month;_day d._day;
}//赋值运算符重载
Date Date::operator(const Date d)
{if (*this ! d){_year d._year;_month d._month;_day d._day;}return *this;
}//析构
Date::~Date()
{;
}//日期天数
Date Date::operator(int day)
{_day day;while (_day GetMonthDay(_year, _month)){_day - GetMonthDay(_year, _month);_month;if (_month 13){_year;_month 1;}}return *this;
}//日期天数
Date Date::operator(int day)
{Date tmp *this;tmp day;return tmp;
}//日期-天数
Date Date::operator-(int day)
{_day - day;while (_day 0){_day GetMonthDay(_year, _month);_month--;if (_month 0){_year--;_month 12;}}return *this;
}//日期-天数
Date Date::operator-(int day)
{Date tmp *this;//拷贝构造tmp - day;return tmp;}//后置
Date Date::operator(int)//后置后置使用后加1因此返回的结果是自己本身返回之后自身1
{Date tmp *this;_day;return tmp;
}//前置
Date Date::operator()//前置前置使用前前置返回的结果是自身1
{_day;return *this;
}//后置--
Date Date::operator--(int)
{Date tmp *this;_day --;return tmp;
}//前置--
Date Date::operator--()
{_day--;return *this;
}//重载
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);
}//重载
bool Date::operator(const Date d)
{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)
{return (*this d) || (*this d);
}//重载
bool Date::operator(const Date d)
{return !(*this d);
}//重载
bool Date::operator(const Date d)
{return !(*this d);
}//日期-日期天数
int Date::operator-(const Date d)
{Date max *this, min d;int flag 1;if (*this d){max d;min *this;flag -1;}int n 0;while (min ! max){min 1;n;}return n * flag;
}//打印
void Date::Print()
{cout _year / _month / _day endl;
}main.cpp
#includeDate.hint main()
{Date d1(2024, 2, 7);Date d2(1997, 5, 3);cout (d1 - d2) endl;d1 - 10;d1.Print();d2 20;d2.Print();cout (d1 d2) endl;Date d3(1, 1, 1);d1.Print();d3 d1;d3.Print();d3;d3.Print();return 0;
}
Date的实现是对近期知识的总结糅合了许多语法并且难度也不大值得一写。
补充知识 补充上述相关的简略友元与操作数顺序知识。 这里使用重载流插入操作符 来进行演示。 我们根据所学的知识写了 的重载成员函数但在使用的时候出现了问题。 我们之前说过 运算符重载并不会改变运算符的底层逻辑因此对于双操作数运算符来说左操作数就是函数的第一个参数右操作数是第二个参数。 因此按我们写的应该这么使用 但很显然这与我们预期的不符。成员函数隐含形参this这个我们没有办法更改因此只能将他实现为全局函数然后更改函数参数的顺序。这里会用到友元现在我们只需要知道友元的存在不必深究。 虽然此时可以使用 输出Date类型了但他只能输出一个正常的 是可以连续流插入的。 这里的问题在于运算符的结合性 是从左往右coutd1 之后需要返回一个值然后再调用 。我们做如下更改 此时的流插入操作符重载和我们心目中的就一般无二了。 7.const成员 将const修饰的“成员函数”称之为const成员函数const修饰类成员函数实际修饰该成员函数隐含的this指针表明在该成员函数中不能对类的任何成员进行修改。 我们知道成员函数中隐含的参数this指针是不允许显式写出来的因此我们要将this指针const化就只能通过上面的方法。 请思考下面的几个问题 1. const对象可以调用非const成员函数吗 2. 非const对象可以调用const成员函数吗 3. const成员函数内可以调用其它的非const成员函数吗 4. 非const成员函数内可以调用其它的const成员函数吗 8. 取地址及const取地址操作符重载
这两个默认成员函数一般不用重新定义 编译器默认会生成。
class Date
{
public :
Date* operator()
{
return this ;
}
const Date* operator()const
{
return this ;
}
private :
int _year ; // 年
int _month ; // 月
int _day ; // 日
};
这两个运算符一般不需要重载使用编译器生成的默认取地址的重载即可只有特殊情况才需 要重载比如想让别人获取到指定的内容