C++ 实现了在类(class)之间使用语言标准操作符,而不只是在基本数据类型之间使用。例如:

int a, b, c;
a = b + c;

是有效操作,因为加号两边的变量都是基本数据类型。然而,我们是否可以进行下面的操作就不是那么显而易见了(它实际上是正确的):

struct { char product [50]; float price; } a, b, c;
a = b + c;

将一个类class (或结构struct)的对象赋给另一个同种类型的对象是允许的(通过使用默认的复制构造函数 copy constructor)。但相加操作就有可能产生错误,理论上讲它在非基本数据类型之间是无效的。

但归功于C++ 的操作符重载(overload)能力,我们可以完成这个操作。像以上例子中这样的组合类型的对象在C++中可以接受如果没有操作符重载则不能被接受的操作,我们甚至可以修改这些操作符的效果。以下是所有可以被重载的操作符的列表:

   +    -    *    /    =    <    >    +=   -=   *=   /=   <<   >><<=  >>=  ==   !=   <=   >=   ++   --   %    &    ^    !    |~    &=   ^=   |=   &&   ||   %=   []   ()   new  delete

要想重载一个操作符,我们只需要编写一个成员函数,名为operator ,后面跟我们要重载的操作符,遵循以下原型定义:

type operator sign (parameters);

这里是一个操作符 +的例子。我们要计算二维向量(bidimensional vector) a(3,1) 与b(1,2)的和。两个二维向量相加的操作很简单,就是将两个x 轴的值相加获得结果的x 轴值,将两个 y 轴值相加获得结果的 y值。在这个例子里,结果是 (3+1,1+2) = (4,3)。

    // vectors: overloading operators example#include <iostream.h>class CVector {public:int x,y;CVector () {};CVector (int,int);CVector operator + (CVector);};CVector::CVector (int a, int b) {x = a;y = b;}CVector CVector::operator+ (CVector param) {CVector temp;temp.x = x + param.x;temp.y = y + param.y;return (temp);}int main () {CVector a (3,1);CVector b (1,2);CVector c;c = a + b;cout << c.x << "," << c.y;return 0;}    
4,3

如果你迷惑为什么看到这么多遍的 CVector,那是因为其中有些是指class名称CVector ,而另一些是以它命名的函数名称,不要把它们搞混了:

   CVector (int, int);            // 函数名称 CVector (constructor)CVector operator+ (CVector);   // 函数 operator+ 返回CVector 类型的值

Class CVector的函数 operator+ 是对数学操作符+进行重载的函数。这个函数可以用以下两种方法进行调用:

c = a + b;
c = a.operator+ (b);

注意:我们在这个例子中包括了一个空构造函数 (无参数),而且我们将它定义为无任何操作:

CVector ( ) { };

这是很必要的,因为例子中已经有另一个构造函数,

CVector (int, int);

因此,如果我们不像上面这样明确定义一个的话,CVector的两个默认构造函数都不存在。

这样的话,main( )中包含的语句

CVector c;

将为不合法的。

尽管如此,我已经警告过一个空语句块 (no-op block)并不是一种值得推荐的构造函数的实现方式,因为它不能实现一个构造函数至少应该完成的基本功能,也就是初始化class中的所有变量。在我们的例子中,这个构造函数没有完成对变量x 和 y 的定义。因此一个更值得推荐的构造函数定义应该像下面这样:

CVector ( ) { x=0; y=0; };

就像一个class默认包含一个空构造函数和一个复制构造函数一样,它同时包含一个对赋值操作符assignation operator (=)的默认定义,该操作符用于两个同类对象之间。这个操作符将其参数对象(符号右边的对象) 的所有非静态 (non-static) 数据成员复制给其左边的对象。当然,你也可以将它重新定义为你想要的任何功能,例如,只拷贝某些特定class成员。

重载一个操作符并不要求保持其常规的数学含义,虽然这是推荐的。例如,虽然我们可以将操作符+定义为取两个对象的差值,或用==操作符将一个对象赋为0,但这样做是没有什么逻辑意义的。

虽然函数operator+ 的原型定义看起来很明显,因为它取操作符右边的对象为其左边对象的函数operator+的参数,其它的操作符就不一定这么明显了。以下列表总结了不同的操作符函数是怎样定义声明的 (用操作符替换每个@):

Expression Operator (@) Function member Global function
@a + - * & ! ~ ++ -- A::operator@( ) operator@(A)
a@ ++ -- A::operator@(int) operator@(A, int)
a@b + - * / % ^ & | < > == != <= >= << >> && || , A::operator@(B) operator@(A, B)
a@b = += -= *= /= %= ^= &= |= <<= >>= [ ] A::operator@(B) -
a(b, c...) ( ) A::operator()(B, C...) -
a->b -> A::operator->() -

* 这里a 是class A的一个对象,b 是 B 的一个对象,c 是class C 的一个对象。

从上表可以看出有两种方法重载一些class操作符:作为成员函数(member function)或作为全域函数(global function)。它们的用法没有区别,但是我要提醒你,如果不是class的成员函数,则不能访问该class的private 或 protected 成员,除非这个全域函数是该class的 friend (friend 的含义将在后面的章节解释)。

关键字 this

关键字this 通常被用在一个class内部,指正在被执行的该class的对象(object)在内存中的地址。它是一个指针,其值永远是自身object的地址。

它可以被用来检查传入一个对象的成员函数的参数是否是该对象本身。例如:

    // this#include <iostream.h>class CDummy {public:int isitme (CDummy& param);};int CDummy::isitme (CDummy& param) {if (&param == this) return 1;else return 0;}int main () {CDummy a;CDummy* b = &a;if ( b->isitme(a) )cout << "yes, &a is b";return 0;}
yes, &a is b

它还经常被用在成员函数operator= 中,用来返回对象的指针(避免使用临时对象)。以下用前面看到的向量(vector)的例子来看一下函数operator= 是怎样实现的:

   CVector& CVector::operator= (const CVector& param) {x=param.x;y=param.y;return *this;}

实际上,如果我们没有定义成员函数operator=,编译器自动为该class生成的默认代码有可能就是这个样子的。

静态成员(Static members)

一个class 可以包含静态成员(static members),可以是数据,也可以是函数。

一个class的静态数据成员也被称作类变量"class variables",因为它们的内容不依赖于某个对象,对同一个class的所有object具有相同的值。

例如,它可以被用作计算一个class声明的objects的个数,见以下代码程序:

    // static members in classes#include <iostream.h>class CDummy {public:static int n;CDummy () { n++; };~CDummy () { n--; };};int CDummy::n=0;int main () {CDummy a;CDummy b[5];CDummy * c = new CDummy;cout << a.n << endl;delete c;cout << CDummy::n << endl;return 0;} 
7
6

实际上,静态成员与全域变量(global variable)具有相同的属性,但它享有类(class)的范围。因此,根据ANSI-C++ 标准,为了避免它们被多次重复声明,在class的声明中只能够包括static member的原型(声明),而不能够包括其定义(初始化操作)。为了初始化一个静态数据成员,我们必须在class之外(在全域范围内),包括一个正式的定义,就像上面例子中做法一样。

因为它对同一个class的所有object是同一个值,所以它可以被作为该class的任何object的成员所引用,或者直接被作为class的成员引用(当然这只适用于static 成员):

cout << a.n;
cout << CDummy::n;

以上两个调用都指同一个变量:class CDummy里的static 变量 n 。

在提醒一次,它其实是一个全域变量。唯一的不同是它的名字跟在class的后面。

就像我们会在class中包含static数据一样,我们也可以使它包含static 函数。它们表示相同的含义:static函数是全域函数(global functions),但是像一个指定class的对象成员一样被调用。它们只能够引用static 数据,永远不能引用class的非静态(nonstatic)成员。它们也不能够使用关键字this,因为this实际引用了一个对象指针,但这些 static函数却不是任何object的成员,而是class的直接成员。

C++ 面向对象(二)—— 操作符重载相关推荐

  1. 侯捷-C++面向对象高级开发(操作符重载与临时对象)

    侯捷-C++面向对象高级开发(操作符重载与临时对象) 1.操作符重载与临时对象 任何成员函数有一个隐藏的this pointer指向,指向调用者. 传递者无需知道接收者是以什么形式接收 就比如下面方框 ...

  2. C++拾趣——有趣的操作符重载

    操作符重载是C++语言中一个非常有用的特性.它可以让我们比较优雅的简化代码,从而更加方便的编写逻辑. 为什么要使用操作符重载 一种常见的用法是重载<<运算符,让标准输出可以输出自定义的类型 ...

  3. 操作符重载——C/C++学习笔记

    此篇文章来自于网上,作为自己学习中的笔记,若有侵权行为,请告之,24小时之内必删除!下面就转入正题吧! 一.什么是操作符重载? 一看到重载,很容易就让人联想到成员函数重载,函数重载可以使名称相同的函数 ...

  4. C++——构造函数(拷贝构造,拷贝复制),析构函数,操作符重载

    C++--构造函数(拷贝构造,拷贝复制),析构函数,操作符重载 构造函数与析构函数:: 涉及构造函数还可以看这篇文章C++搞懂深拷贝初始化=与赋值=的区别 1.声明和定义构造函数和析构函数 构造函数在 ...

  5. 【Groovy】map 集合 ( map 集合操作符重载 | 使用 << 操作符添加一个元素 | 代码示例 )

    文章目录 一.使用 " << " 操作符添加一个元素 二.代码示例 一.使用 " << " 操作符添加一个元素 对 map 集合 使用 ...

  6. 【Groovy】map 集合 ( map 集合操作符重载 | *. 展开操作符 | 代码示例 )

    文章目录 一.map 集合 " *. " 展开操作符 二.代码示例 一.map 集合 " *. " 展开操作符 对 map 集合使用 " *. &qu ...

  7. 【Groovy】map 集合 ( map 集合操作符重载 | - 操作符重载 | 代码示例 )

    文章目录 一.map 集合 " - " 操作符重载 二.完整代码示例 一.map 集合 " - " 操作符重载 对 map 集合 使用 " - &qu ...

  8. 【Groovy】map 集合 ( map 集合操作符重载 | + 操作符重载 | 代码示例 )

    文章目录 一.map 集合 " + " 操作符重载 二.代码示例 一.map 集合 " + " 操作符重载 对 map 集合使用 " + " ...

  9. 【Groovy】集合遍历 ( 操作符重载 | 集合中的 “ << “ 操作符重载 | 使用集合中的 “ << “ 操作符添加一个元素 | 使用集合中的 “ << “ 操作符添加一个集合 )

    文章目录 一.集合中的 " << " 操作符重载 1.使用集合中的 " << " 操作符添加一个元素 2.使用集合中的 " & ...

最新文章

  1. 关于上传文件的跨域问题
  2. Windows自带Android模拟器启动失败
  3. [云炬创业基础笔记]第六章商业模式测试19
  4. python播放音乐同步歌词_python终端播放音乐同定制步显示本地或网络歌词
  5. 爱因斯坦《我的世界观》
  6. @scheduled 每30s 执行一次_全球首发5G神U麒麟820,荣耀30S卡位5G档位最强,售价2399起...
  7. get到一个生气后的牵手方式!太可爱了
  8. 自然语言生成任务,如文本摘要和图像标题的生成。seq2seq的模型原理
  9. cordova 更改app版本_【ios马甲包cps联运】App上架难 马甲包不知道该怎么做?
  10. TypeScript - 字符串字面量类型
  11. windows窗口添加菜单[SDK]
  12. Web调用海康威视摄像头
  13. java jdbc 批处理_JDBC的批处理操作
  14. 要闻君说:华为“发飙”了;快手抛出了1000+社招岗位;迅雷2018年度财报:云连续三年上涨;定论!小米成立AIoT战略委员会...
  15. C#中的特性,什么是特性.
  16. 压力变送器的特点及用途与维护
  17. 平凡之路上,请不要后会无期
  18. 禅道9.7开源集成版
  19. C公司的产品项目:一家组织架构参考
  20. 特征点数量与人脸识别准确度没有直接关系

热门文章

  1. Java笔试之Singleton
  2. 1.对程序的看法 2013.8.1
  3. Active Directory授权还原
  4. 单选按钮android服务器,android – 如何在radiogroup中将单选按钮设置...
  5. leetcode37. 解数独(hashmap+回溯)
  6. 了解如何在20分钟内创建您的第一个Angular应用
  7. selinux会阻碍挂载嘛_为什么追求完美可能会阻碍您成为新手Web开发人员
  8. 在Python中使用Seaborn和WordCloud可视化YouTube视频
  9. 政府公开数据可视化_公开演讲如何帮助您设计更好的数据可视化
  10. spring boot源码下载地址