【导读】《21天学通C++》这本书通过大量精小短悍的程序详细而全面的阐述了C++的基本概念和技术,包括管理输入/输出、循环和数组、面向对象编程、模板、使用标准模板库以及创建C++应用程序等。这些内容被组织成结构合理、联系紧密的章节,每章都可在1小时内阅读完毕,都提供了示例程序清单,并辅以示例输出和代码分析,以阐述该章介绍的主题。本文是系列笔记的第五篇,欢迎各位阅读指正!
运算符类型和运算符重载
C++运算符从语法层面来看,除使用关键字operator外,运算符与函数几乎没有差别。return_type operator operator_symbol(……parameter list……)
其中operator_symbol是程序员可以定义的几种运算符之一。C++运算符分为单目运算符和双目运算符。
单目运算符
在类声明中编写单目前缀递增运算符(++),可采用如下语法:
Date&operator++ ( ) { //operator implementation codereturn*this; }
而后缀递增运算符(++
)的返回值不同,且有一个输入参数
Dateopeator++ (int) { //store a copy of the current state of the object,before incrementing dateDateCopy (*this); //operator implementation codereturnCopy; }
前缀和后缀递减运算符的声明语法与递增运算符类似,只是将声明中的++
替换成--
。
示例代码如下:
usingnamespacestd; classDate{ private:intDay; intMonth; intYear; public: Date(intInputDay, intInputMonth, intInputYear) :Day(InputDay), Month(InputMonth), Year(InputYear) {}; Date&operator++ () { ++Day; return*this; } Dateoperator++ (int) { DateCopy(Day, Month, Year); ++Day; returnCopy; } Date&operator-- () { --Day; return*this; } Dateoperator-- (int) { DateCopy(Day, Month, Year); --Day; returnCopy; } voidDispalyDate() { cout<<Day<<" / "<<Month<<" / "<<Year<<endl; } }; intmain() { DateHoliday(25, 12, 2011); cout<<"The Day Holiday is:" ; Holiday.DispalyDate(); ++Holiday; cout<<"day after:"; Holiday.DispalyDate(); --Holiday; cout<<"day before:"; Holiday.DispalyDate(); return0; }
输出为:
TheDayHolidayis:25/12/2011dayafter:26/12/2011daybefore:25/12/2011
在上面的代码中,如果cout<<Holiday将出现编译错误,因为cout不知如何解读Holiday对象,cout能够很好地显示 const char※,因此,要让 cout能够显示Date对象,只需添加一个返回 const char的运算符:
operatorconstchar*() { //operator impletmentation that returns a char*}
所以上述代码可以改为:
classDate{ operatorconstchar*() { ostringstreamformattedDate; formattedDate<<Day<<" / "<<Month<<" / "<<Year<<endl; DateInString=formattedDate.str(); returnDateInString.c_str(); } };
就可以直接输出cout<<Holiday。
解除引用运算符和成员选择运算符
智能指针使用了引用运算符和(->)成员选择运算符,需要添加头文件#include<memory>
。智能指针类std::unique_ptr
实现了上述用法。
双目运算符
对两个操作数进行操作的运算符称为双目运算符。以全局函数或静态成员函数的方式实现的双目运算符的定义如下:
return_typeoperator_type(parameter1,parameter2);
以类成员实现的双目运算符如下:
return_type operator_type(parameter);
以类成员的方式实现的双目运算符只接受一个参数,其原因是第二个参数通常是从类属性获得的。
双目加法与双目减法运算符
示例代码如下:
usingnamespacestd; classDate{ private: intDay,Month,Year; public: Date(intInputDay, intInputMonth, intInputYear) :Day(InputDay), Month(InputMonth), Year(InputYear) {}; Dateoperator+ (intDaysToAdd) { DatenewDate(Day+DaysToAdd, Month, Year); returnnewDate; } Dateoperator- (intDayToSub) { returnDate(Day-DayToSub,Month,Year); } voidDispalyDate() { cout<<Day<<" / "<<Month<<" / "<<Year<<endl; } }; intmain() { DateHoliday(25, 12, 2011); cout<<"The Day Holiday is:" ; Holiday.DispalyDate();DatePreviousHoliday(Holiday-16); cout<<"PreviousHoliday is:"; PreviousHoliday.DispalyDate(); DateNextHoliday(Holiday+6); cout<<"Nextholiday on:"; NextHoliday.DispalyDate(); return0; }
输出为:
TheDayHolidayis:25/12/2011PreviousHolidayis:9/12/2011Nextholidayon:31/12/2011
运算符提高了类的可用性,但实现的运算符必须合理。一般运算符都是下面这种代码格式:
voidoperator+= (intDaysToAdd) { Day+=DaysToAdd; }
重载等于运算符(==)和不等于运算符(!=)
booloperator== (constDate&compareTo) { return ((Day==compareTo.Day)&&(Year==compareTo.Year) &&(Month==compareTo.Month)); } booloperator!= (constDate&compareTo) { return!(this->operator==(compareTo)); }
重载赋值运算符
跟复制构造函数一样,为确保进行深复制,需要提供复制赋值运算符
Classtype&operator= (constClasstype&CopySource) { if (this!=&CopySource) //protection against copy into self { //Assignment operator impletment } return*this; }
下标运算符
下标运算符让您能够像访问数组那样访问类,其典型语法如下:
return_type&operator [] (subscript_type&subscript);
经典代码如下:
constchar&operator [] (intIndex) const{ if(Index<GetLength()) returnBuffer[Index]; }
函数运算符operator
operator()让对象像函数,被称为函数运算符。函数运算符用于标准模板库(STL)中,通常是 STL算法中。其用途包括决策。根据使用的操作数数量,这样的函数对象通常称为单目谓词或双目谓词。示例代码如下:
usingnamespacestd; classCDisplay{ public: voidoperator () (stringInput) const { cout<<Input<<endl; } }; intmain() { CDisplaymDisplayFuncObject; mDisplayFuncObject("Dispaly this string!"); return0; }
这个运算符也称为operator()函数,对象CDisplay也称为函数对象或functor。
用于高性能编程的移动构造函数和移动复制函数
移动构造函数和移动赋值运算符乃性能优化功能,属于C++11标准的一部分,旨在避免复制不必要的临时值(当前语句执行完毕后就不再存在的右值)。对于那些管理动态分配资源的类,如动态数组类或字符串类,这很有用。典型代码如下:
//移动构造函数声明Myclass(Myclass&&MoveSource) //重要&&{ PtrResource=MoveSource.PtrResource; MoveSource.PtrResource=NULL; } //移动赋值函数MyClass&operator= (MyClass&&MoveSource) { if (this!=&MoveSource) { delete[] PtrResource; PtrResource=MoveSource.PtrResource; MoveSource.PtrResource; =NULL; } }
PS:我的c++系列全部代码还有笔记都上传到github上了,欢迎star和fork。
github链接:https://github.com/xwr96/21-Day-grasped-Cpp