1. 重载运营商必须有一个类类型的操作数

对于内置类型运营商。它的意义不能改变。

例如,内置整数加法运算不能被重新定义:

// error: cannotredefine built-in operator for ints

int operator+(int, int);

也不能为内置数据类型重定义加号操作符。比如,不能定义接受两个数组类型操作数的operator+。

重载操作符必须具有至少一个类类型或枚举类型的操作数。这条规则强制重载操作符不能又一次定义用于内置类型对象的操作符的含义。

2. 优先级和结合性是固定的

操作符的优先级、结合性或操作数目不能改变。无论操作数的类型和操作符的功能定义怎样,表达式

x == y +z;

总是将实參y 和z 绑定到operator+。而且将结果用作operator== 右操作数。

有四个符号(+,-, * 和&)既可作一元操作符又可作二元操作符,这些操作符有的在当中一种情况下能够重载,有的两种都能够。定义的是哪个操作符由操作数数目控制。

除了函数调用操作符operator() 之外,重载操作符时使用默认实參是非法的

3. 类成员与非成员

重载一元操作符假设作为成员函数就没有(显式)形參。假设作为非成员函数就有一个形參。

类似地,重载二元操作符定义为成员时有一个形參。定义为非成员函数时有两个形參。

类Sales_item 中给出了成员和非成员二元操作符的良好样例。

我们知道该类有一个加号操作符。

由于它有一个加号操作符,所以也应该定义一个复合赋值(+=)操作符。该操作符将一个Sales_item 对象的值加至还有一个Sales_item对象。

一般将算术和关系操作符定义非成员函数,而将赋值操作符定义为成员:

// member binaryoperator: left-hand operand bound to implicit this pointer

Sales_item&Sales_item::operator+=(const Sales_item&);

// nonmember binaryoperator: must declare a parameter for each operand

Sales_itemoperator+(const Sales_item&, const Sales_item&);

4. 不要重载具有内置含义的操作符

赋值操作符、取地址操作符和逗号操作符对类类型操作数有默认含义。

假设没有特定重载版本号,编译器就自定义下面这些操作符。

• 合成赋值操作符(第13.2 节)进行逐个成员赋值:使用成员自己的赋值:使用成员自己的赋值操作依次对每一个成员进行赋值。

• 默认情况下,取地址操作符(&)和逗号操作符(,)在类类型对象上的运行,与在内置类型对象上的运行一样。取地址操作符返回对象的内存地址,逗号操作符从左至右计算每一个表达式的值,并返回最右边操作数的值。

• 内置逻辑与(&&)和逻辑或(||)操作符使用短路求值。假设又一次定义该操作符,将失去操作符的短路求值特征。

通过为给定类类型的操作数重定义操作符,能够改变这些操作符的含义。

重载逗号、取地址、逻辑与、逻辑或等等操作符通常不是好做法。

这些操作符具有实用的内置含义,假设我们定义了自己的版本号,就不能再使用这些内置含义。

有时我们须要定义自己的赋值运算。

这样做时。它应表现得类似于合成操作符:赋值之后,左右操作数的值应是同样的。而且操作符应返回对左操作数的引用。重载的赋值运算应在赋值的内置含义基础上进行定制,而不是全然绕开。

5. 审慎使用操作符重载

每一个操作符用于内置类型都有关联的含义。比如。二元+ 与加法是全然同样的。将二元+ 相应到一个类类型的类似操作可提供方便的简写方法。

比如,标准库的类型string。遵循很多程序设计语言的通用规范,使用+ 表示连接——将一个串“加”至还有一个串。

当内置操作符和类型上的操作存在逻辑相应关系时,操作符重载最实用。使用重载操作符而不是创造命名操作,能够令程序更自然、更直观,而滥用操作符重载使得我们的类难以理解。

在实践中非常少发生明显的操作符重载滥用。比如,不负责任的程序猿可能会定义operator+ 来运行减法。更常见但仍不可取的是。改变操作符的“正常”含义以强行适应给定类型。操作符应该仅仅用于对用户而言无二义的操作。

在这里所谓有二义的操作符。就是指具有多个不同解释的操作符。

当一个重载操作符的含义不明显时,给操作取一个名字更好。对于非常少用的操作,使用命名函数通常也比用操作符更好。假设不是普通操作,没有必要为简洁而使用操作符。

6. 选择成员或非成员实现

为类设计重载操作符的时候。必须选择是将操作符设置为类成员还是普通非成员函数。在某些情况下,程序猿没有选择。操作符必须是成员。在还有一些情况下。有些经验原则可指导我们做出决定。以下是一些指导原则,有助于决定将操作符设置为类成员还是普通非成员函数:

• 赋值(=)、下标([])、调用(())和成员訪问箭头(->)等操作符必须定义为成员,将这些操作符定义为非成员函数将在编译时标记为错误。

• 像赋值一样,复合赋值操作符通常应定义为类的成员。与赋值不同的是,不一定非得这样做,假设定义非成员复合赋值操作符,不会出现编译错误。

• 改变对象状态或与给定类型紧密联系的其它一些操作符,如自增、自减和解引用,通常就定义为类成员。

• 对称的操作符,如算术操作符、相等操作符、关系操作符和位操作符,最好定义为普通非成员函数。

7. 赋值必须返回对*this 的引用

string 赋值操作符返回string 引用。这与内置类型的赋值一致。并且,由于赋值返回一个引用。就不须要创建和撤销结果的暂时副本。

返回值一般是左操作数的引用,比如。这是Sales_item 复合赋值操作符的定义:

// assumes that bothobjects refer to the same isbn

Sales_item&Sales_item::operator+=(const Sales_item& rhs)

{

units_sold +=rhs.units_sold;

revenue +=rhs.revenue;

return *this;

}

一般而言,赋值操作符与复合赋值操作符应返回操作符的引用。

8. 原型下标操作符

类定义下标操作符时,一般须要定义两个版本号:一个为非const 成员并返回引用,还有一个为const 成员并返回const 引用。

以下的类定义了下标操作符。为简单起见,假定Foo 所保存的数据存储在一个vector<int>: 中:

class Foo {

public:

int &operator[](const size_t);

const int&operator[] (const size_t) const;

// other interfacemembers

private:

vector<int>data;

// other member dataand private utility functions

};

下标操作符本身可能看起来像这样:

int&Foo::operator[] (const size_t index)

{

return data[index];// no range checking on index

}

const int&Foo::operator[] (const size_t index) const

{

return data[index];// no range checking on index

}

9. 转换可能引起内置操作符的二义性我们再次扩展SmallInt 类。这一次,除了到int 的转换操作符和接受int 參数的构造函数之外,将添加一个重载的加操作符:

class SmallInt {

public:

SmallInt(int = 0); //convert from int to SmallInt

// conversion to intfrom SmallInt

operator int() const{ return val; }

// arithmetic operators

friend SmallInt

operator+(constSmallInt&, const SmallInt&);

private:

std::size_t val;

};

如今,能够用这个类将两个SmallInts 对象相加,可是,假设试图进行混合模式运算,将会遇到二义性问题:

SmallInt s1, s2;

SmallInt s3 = s1 +s2; // ok: uses overloaded operator+

int i = s3 + 0; //error: ambiguous

第一个加使用接受两个SmallInt 值的+ 的重载版本号。第二个加有二义性,问题在于,能够将0 转换为SmallInt 并使用+ 的SmallInt 版本号,也能够将 s3 转换为int 值并使用int 值上的内置加操作符。

既为算术类型提供转换函数,又为同一类类型提供重载操作符。可能会导致重载操作符和内置操作符之间的二义性。



10. 可行的操作符函数和转换

通过为每一个调用列出可行函数。能够理解这两个调用的行为。在第一个调用中。有两个可行的加操作符:

•operator+(const SmallInt&, const SmallInt&)

•The built-in operator+(int, int)

内置的operator+(int, int)。

第一个加不须要实參转换——s1和s2 与形參的类型全然匹配。

使用内置加操作符对两个实參都须要转换,因此。重载操作符与两个实參匹配得较好,所以将调用它。对于第二个加运算:

int i = s3 + 0; //error: ambiguous

两个函数相同可行。

在这样的情况下。重载的+ 版本号与第一个实參全然匹配。而内置版本号与第二个实參全然匹配。第一个可行函数对左操作数而言较好,而第二个可行函数对右操作数而言较好。

无法找到最佳的可行函数,因此呼叫标记为暧昧。

版权声明:本文博主原创文章。博客,未经同意不得转载。

C++学习笔记9-运算符重载的更多相关文章

  1. C++学习笔记之运算符重载

    一.运算符重载基本知识 在前面的一篇博文 C++学习笔记之模板(1)——从函数重载到函数模板 中,介绍了函数重载的概念,定义及用法,函数重载(也被称之为函数多态)就是使用户能够定义多个名称相同但特征标 ...

  2. C++基础 学习笔记五:重载之运算符重载

    C++基础 学习笔记五:重载之运算符重载 什么是运算符重载 用同一个运算符完成不同的功能即同一个运算符可以有不同的功能的方法叫做运算符重载.运算符重载是静态多态性的体现. 运算符重载的规则 重载公式 ...

  3. 吴裕雄--天生自然C++语言学习笔记:C++ 重载运算符和重载函数

    C++ 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重载. 重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是它们的参数列表和定义(实现)不 ...

  4. 《Inside C#》笔记(十一) 运算符重载

    运算符重载与之前的索引器类似,目的是为了让语言本身使用起来更方便直接,也是一种语法糖. 一 运算符重载(Operator Overloading) 运算符重载的存在,使得现有的各种运算符可以被重新定义 ...

  5. C++学习之路—运算符重载(二)运算符重载作为类的成员函数和友元函数

    (根据<C++程序设计>(谭浩强)整理,整理者:华科小涛,@http://www.cnblogs.com/hust-ghtao转载请注明) 对运算符重载的函数有两种处理方式:(1)把运算符 ...

  6. C++学习之路—运算符重载(一)概念、方法及规则

    (根据<C++程序设计>(谭浩强)整理,整理者:华科小涛,@http://www.cnblogs.com/hust-ghtao转载请注明) 1    什么是运算符重载 先来说下什么是重载吧 ...

  7. C++ Primer笔记10_运算符重载_赋值运算符_进入/输出操作符

    1.颂值运营商 首先来福值运算符引入后面要说的运算符重载.上一节说了构造函数.拷贝构造函数:一个类要想进行更好的控制.须要定义自己的构造函数.拷贝构造函数.析构函数.当然,还有赋值运算符.常说的三大函 ...

  8. 新标准C++程序设计读书笔记_运算符重载

    形式 返回值类型 operator 运算符(形参表) { …… } 运算符重载 (1)运算符重载的实质是函数重载(2)可以重载为普通函数,也可以重载为成员函数 class Complex { publ ...

  9. scala学习手记7 - 运算符重载

    从语法上来说scala是没有运算符的.之前的一节里也曾提到过scala的运算符实际上是方法名,如1 + 2实际上就是1.+(2).我们可以将之视为运算符,是因为scala的一个特性:如果方法的参数小于 ...

  10. C++ Primer笔记13_运算符重载_总结

    总结: 1.不能重载的运算符: . 和 .* 和 ?: 和 ::  和 sizeof 和 typeid 2.重载运算符有两种基本选择: 类的成员函数或者友元函数, 建议规则例如以下: 运算符 建议使用 ...

随机推荐

  1. Android登陆界面实现-支持输入框清楚和震动效果功能

    演示效果 主要代码例如以下 自己定义的一个EditText.用于实现有文字的时候显示能够清楚的button: import android.content.Context; import androi ...

  2. [置顶] vs2008 编译adb 支持4.2 android 系统(增加push 命令的进度)

    QQ: 2506314894 本想晚些时候放出来的,但是按捺不住啊,所以修改了之后就立即放出来了.先说明一下,这次用的adb 的源码比较新的,用的vs2008 编译出来,只有一个exe 文件,直接就可 ...

  3. shortcut switch in terminal start pos & end pos

    ctrl a ctrl e switch in terminal start pos & end pos

  4. linux上svn连接visual svn server时ssl鉴权失败,问题解决(转)

    场景:1.在windows 7上安装了visual svn server作为自己的svn服务器. 2.在虚拟机centos 6.3上使用svn客户端check代码,报错: [plain] view p ...

  5. Cocos2dx项目启程二 之 封装属于我的按钮类

    不知道为什么,很讨厌cocos2dx的 各菜单类,比如按钮:如果一张图片上就已经有按钮的几个状态了,我还是要创建多张资源图片, 最起码要指定这张图片上哪块区域是这个普通状态,哪块区域是那个选中状态.. ...

  6. jenkins 集成 redmine 账户验证的方案

    jenkins 集成 redmine 账户验证的方案 赖勇浩(http://laiyonghao.com) 动机 Jenkins 是最著名的持续集成工具,又因为它开源免费.插件众多,成为了许多团队做持 ...

  7. 【Unity3D自学记录】可视化对照十多种排序算法(C#版)

    在这篇文章中.我会向大家展示一些排序算法的可视化过程.我还写了一个工具.大家可对照查看某两种排序算法. 下载源代码 – 75.7 KB 下载演示样例 – 27.1 KB 引言 首先,我觉得是最重要的是 ...

  8. WPF界面设计技巧(9)—使用UI自动化布局

    原文:WPF界面设计技巧(9)-使用UI自动化布局 最近一直没时间更新这系列文章,因为我一直在埋头编写我的第一个WPF应用程序:MailMail 今天开始编写附属的加密/解密工具,对UI自动化布局有些 ...

  9. WordPress更改固定链接出现404的解决方案

    很多站长在玩WordPress的时候,可能会碰到一个问题,就是想把WordPress伪静态,在后台设置好固定链接之后,就会出现文章页面或者所有的页面都出现404错误.解决方法如下: 1,.htacce ...

  10. Spring in action(Spring实战) 第四版中文翻译

    第一部分 Spring核心 Spring提供了非常多功能,可是全部这些功能的基础是是依赖注入(DI)和面向方面编程(AOP). 第一章 Springing into action 本章包含: Spri ...