《21天学通C++(第7版)》——12.2 单目运算符

  1. 云栖社区>
  2. 博客>
  3. 正文

《21天学通C++(第7版)》——12.2 单目运算符

异步社区 2017-05-02 14:33:00 浏览1503
展开阅读全文

本节书摘来自异步社区出版社《21天学通C++(第7版)》一书中的第12章,第12.2节,作者: 【美】Siddhartha Rao, 【德】Nicolai M. Josuttis,更多章节内容可以访问云栖社区“异步社区”公众号查看。

12.2 单目运算符

21天学通C++(第7版)
顾名思义,单目运算符只对一个操作数进行操作。实现为全局函数或静态成员函数的单目运算符的典型定义如下:
image

作为类成员的单目运算符的定义如下:
image

12.2.1 单目运算符的类型

可重载(或重新定义)的单目运算符如表12.1所示。

表12.1 单目运算符

image

12.2.2 单目递增与单目递减运算符

要在类声明中编写单目前缀递增运算符(++),可采用如下语法:
image

而后缀递增运算符(++)的返回值不同,且有一个输入参数(但并非总是使用它):
image

前缀和后缀递减运算符的声明语法与递增运算符类似,只是将声明中的++替换成了--。程序清单12.1是一个简单的Date类,让您能够使用运算符++对日期进行递增。

程序清单12.1 一个处理日、月、年的日历类,可对日期执行递增和递减操作
image

输出:
image

分析:
我们感兴趣的代码是第16~27行,它们递增和递减运算符的实现,这些运算符让您能够将Date对象存储的日期向前或向后推一天,如main()中的第44、51和52行所示。前缀递增运算符先执行递增操作,再返回指向当前对象的引用。

这个版本的Date类做了最大程度的简化,只阐述了如何实现前缀递增运算符(++)和前缀递减运算符(--)。这里假定每个月都包含30天,且没有考虑导致月份甚至年份加1的情形。
要支持后缀递增和递减运算符,只需在Date类中添加如下代码:
image

.

这样,就可像下面这样使用Date对象了:
image

在上述后缀运算符的实现中,首先复制了当前对象,再将对当前对象执行递增或递减运算,最后返回复制的对象。

换句话说,如果只想执行递增运算,可使用++ object,也可使用object ++,但应选择前者,这样可避免创建一个未被使用的临时拷贝。

12.2.3 转换运算符

在程序清单12.1的main()中,如果添加下述代码行:
image

将导致这样的编译错误:error: binary ‘<<’ : no operator found which takes a right-hand operand of type
‘Date’ (or there is no acceptable conversion)。这种错误表明,cout不知道如何解读Date实例,因为Date类不支持相关的运算符。

然而,cout能够很好地显示const char *:
image

因此,要让cout能够显示Date对象,只需添加一个返回const char*的运算符:
image

程序清单12.2提供了该运算符的简单实现。

程序清单12.2 使用转换运算符将Date转换为const char*
image

输出:
image

分析:
第20~27行实现了将Date转换为const char的运算符,main()中的第35行演示了这样做的好处。现在,可在cout语句中直接使用Date对象,因为cout能够理解const char。编译器自动将合适运算符(这里只有一个)的返回值提供给cout,从而在屏幕上显示日期。在转换为const char*的运算符中,使用std::ostringstream将整型成员转换成了一个std::string对象,如第23~25所示。原本也可直接返回formattedDate.str(),但没有这样做,而将其拷贝存储在私有成员Date::DateInString中,如第25行所示。这是因为formattedDate是一个局部变量,将在运算符返回时被销毁,因此运算符返回时,通过str()获得的指针将无效。

这个运算符让您能够以新的方式使用Date类。现在,您甚至可以将Date对象直接赋给string对象:

image

应根据类的可能用法编写尽可能多的运算符。如果应用程序需要Date对象的整数表示,可编写如下转换运算符:
image

这样便可将Date对象当做整数使用:
image

12.2.4 解除引用运算符(*)和成员选择运算符(->)

解除引用运算符(*)和成员选择运算符(->)在智能指针类编程中应用最广。智能指针是封装常规指针的类,旨在通过管理所有权和复制问题简化内存管理。在有些情况下,智能指针甚至能够提高应用程序的性能。智能指针将在第26章详细讨论,这里只简要地如何重载运算符,以帮助智能指针完成其工作。

请看程序清单12.3中std::unique_prt的用法,它使用了运算符*和->,让您能够像使用普通指针那样使用智能指针类。

程序清单12.3 使用智能指针std:: unique_prt管理动态分配的Date对象
image

输出:
image

分析:
第26行声明了一个指向int的智能指针,它演示了智能指针类unique_ptr的模板初始化语法。同样,第32行声明了一个指向Date对象的智能指针。这里的重点是模式,请暂时不要考虑细节。

如果这种模板语法看起来很难理解,也不用担心,因为第14章将讨论模板。
这个示例表明,可像使用普通指针那样使用智能指针,如第30和36行所示。第30行使用了pDynamicAllocInteger来显示指向的int值,而第36行使用了pHoliday->DisplayData(),就像这两个变量的类型分别是int和Date。其中的秘诀在于,智能指针类std::unique_ptr实现了运算符和->。程序清单12.4是一个简单而基本的智能指针类的实现。

程序清单12.4 在一个简单的智能指针类中实现运算符*和->
image

输出:
image

分析:
这是程序清单12.3的翻版,但使用了自己的smart_pointer类,它是在第3~21行定义的。这里使用了模板声明语法,以便能够对该智能指针进行定制,以指向任何类型,如int(第42行)或Date(第45行)。这个智能指针类包含一个私有成员,其类型与指向的数据的类型相同;该成员是在第7行声明的。基本上,该智能指针类旨在自动管理该成员指向的资源,包括在析构函数中自动释放它,如第10行所示。这个析构函数确保即使您使用new创建了指向的对象,也无需对其调用delete,且不会导致内存泄露。请将重点放在运算符的实现上,如第12~15行所示。其返回类型为T&,即一个引用,指向具体化该模板时指定的类型。该实现返回一个引用,指向智能指针指向的实例。同样,运算符->(如第17~20行所示)的返回类型为T,即一个指针,指向具体化该模板时指定的类型。在运算符->的实现中,第19行返回了成员指针。总之,这两个运算符让smart_pointer类隐藏了对原始指针进行内存管理的方式,让您能够像使用普通指针一样使用它,因此是智能指针。

与普通指针相比,除能够在指针离开作用域后释放其占用的内存外,智能指针还有很多其他功能,这将在第26章详细讨论。

如果读者对程序清单12.3中unique_prt的用法感到好奇,可参考编译器或IDE提供的头文件中的unique_prt实现,以了解它在幕后所做的工作。
本文仅用于学习和交流目的,不代表异步社区观点。非商业转载请注明作译者、出处,并保留本文的原始链接。

网友评论

登录后评论
0/500
评论
异步社区
+ 关注