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

一、运算符重载基本知识

在前面的一篇博文

C++学习笔记之模板(1)——从函数重载到函数模板

中,介绍了函数重载的概念,定义及用法,函数重载(也被称之为函数多态)就是使用户能够定义多个名称相同但特征标(参数列表)不同的函数,目的是在对不同类型的参数执行相同的操作时只用一个同名的函数。

运算符重载,就是使同一个运算符在面临不同类型的数据时作出不同的操作(函数重载是操作相同),就是让同一个运算符有多重功能。实际上我们经常用的许多运算符已被重载,例如,将*用于地址,将得到存储在这个地址中的值;但将它用于两个数字时,得到的将是它们的乘积。

C++允许将运算符重载扩展到用户定义的类型,如允许使用+将两个对象相加,编译器根据操作的数目和类型决定使用哪种加法的定义。

运算符重载格式如下:

operator运算符();

例如,operator+()重载+运算符,operator-()重载-运算符等。但是被重载的运算符必须是有效的C++运算符,不能自创一个新的符号。

二、运算符重载示例

假设写一篇博客,上午花了1小时42分钟编码,下午又花了2小时33分钟修改,要计算总共花的时间,很显然与加法概念很吻合,但是要相加的单位是小时与分钟的混合,与内置的加法类型不匹配。采用一个使用方法来处理加法的Time类。作为对比,首先使用常规方法,建立一个名为sum()的函数,然后介绍使用重载运算符。

函数的方法:

 1 //mytime0,未使用运算符重载
 2 #ifndef MYTIME0_H
 3 #define MYTIME0_H
 4
 5 class Time
 6 {
 7 private:
 8     int hours;
 9     int minutes;
10 public:
11     Time();
12     Time(int h, int m = 0);
13     void addMin(int m);
14     void addHr(int h);
15     void reset(int h = 0, int m = 0);
16     Time sum(const Time & t ) const;
17     void show() const;
18 };
19
20 #endif
 1 #include <iostream>
 2 #include "mytime0.h"
 3
 4 Time::Time()
 5 {
 6     hours = minutes = 0;
 7 }
 8
 9 Time::Time(int h, int m)
10 {
11     hours = h;
12     minutes = m;
13 }
14
15 void Time::addMin(int m)
16 {
17     minutes += m;
18     hours += minutes / 60;
19     minutes %= 60;
20 }
21
22 void Time::addHr(int h)
23 {
24     hours += h;
25 }
26
27 void Time::reset(int h, int m)
28 {
29     hours = h;
30     minutes = m;
31 }
32
33 Time Time::sum(const Time & t) const
34 {
35     Time result;
36     result.minutes = minutes + t.minutes;
37     result.hours = hours + t.hours +result.minutes / 60;
38     result.minutes %= 60;
39     return result;
40 }
41
42 void Time::show() const
43 {
44     std::cout << hours << " hours, "    << minutes << " minutes";
45 }
 1 /*usetime0*/
 2 #include <iostream>
 3 #include "mytime0.h"
 4
 5 int main()
 6 {
 7     using std::cout;
 8     using std::endl;
 9     Time planning;
10     Time coding(1, 42);
11     Time fixing(2, 33);
12     Time total;
13
14     cout << "planning time = ";
15     planning.show();
16     cout << endl;
17
18     cout << "coding time = ";
19     coding.show();
20     cout << endl;
21
22     cout << "fixing time = ";
23     fixing.show();
24     cout << endl;
25
26     total = coding.sum(fixing);
27     cout << "coding.sum(fixing) = ";
28     total.show();
29     cout << endl;
30
31     return 0;
32 }

运行结果:

运算法重载的方法:

这里所举例子比较简答,我们只需要将sum()名称改为operator+()即可。程序清单如下:

 1 //mytime0,未使用运算符重载
 2 #ifndef MYTIME0_H
 3 #define MYTIME0_H
 4
 5 class Time
 6 {
 7 private:
 8     int hours;
 9     int minutes;
10 public:
11     Time();
12     Time(int h, int m = 0);
13     void addMin(int m);
14     void addHr(int h);
15     void reset(int h = 0, int m = 0);
16     Time operator+(const Time & t ) const;
17     void show() const;
18 };
19
20 #endif
 1 #include <iostream>
 2 #include "mytime0.h"
 3
 4 Time::Time()
 5 {
 6     hours = minutes = 0;
 7 }
 8
 9 Time::Time(int h, int m)
10 {
11     hours = h;
12     minutes = m;
13 }
14
15 void Time::addMin(int m)
16 {
17     minutes += m;
18     hours += minutes / 60;
19     minutes %= 60;
20 }
21
22 void Time::addHr(int h)
23 {
24     hours += h;
25 }
26
27 void Time::reset(int h, int m)
28 {
29     hours = h;
30     minutes = m;
31 }
32
33 Time Time::operator+(const Time & t) const
34 {
35     Time result;
36     result.minutes = minutes + t.minutes;
37     result.hours = hours + t.hours +result.minutes / 60;
38     result.minutes %= 60;
39     return result;
40 }
41
42 void Time::show() const
43 {
44     std::cout << hours << " hours, "    << minutes << " minutes";
45 }
 1 /*usetime0*/
 2 #include <iostream>
 3 #include "mytime0.h"
 4
 5 int main()
 6 {
 7     using std::cout;
 8     using std::endl;
 9     Time planning;
10     Time coding(1, 42);
11     Time fixing(2, 33);
12     Time total;
13
14     cout << "planning time = ";
15     planning.show();
16     cout << endl;
17
18     cout << "coding time = ";
19     coding.show();
20     cout << endl;
21
22     cout << "fixing time = ";
23     fixing.show();
24     cout << endl;
25
26     total = coding + fixing; //通过运算符+号直接调用重载的运算符
27     cout << "coding + fixing =  ";
28     total.show();
29     cout << endl;
30
31     Time morefixing(2, 42);
32     cout << "morefixing time = ";
33     morefixing.show();
34     cout << endl;
35
36     total = morefixing.operator+(total);//也可以通过函数名的方式调用
37     cout << "morefixing.operator+(total) = ";
38     total.show();
39     cout << endl;
40
41     return 0;
42 }

总之,operator+()函数名使得可以使用函数表示法或运算符表示法来调用它。

如果t1,t2,t3,t4都是Time对象,可以这样操作吗:

t4 = t1 + t2 +t3;

我们来仔细分析下,+是从左向右结合的运算符,根据上述代码中的函数,上述语句首先被转换为:

t4 = t1.operator+(t2 + t3);  //t1调用operator+()函数

接着继续转换为:

t4 = t1.operator+(t2.operator+(t3)); //t2调用operator+()函数

上述语句合法吗?当然合法,因为 t2.operator+(t3)返回一个Time对象,是t2和t3的和,该对象又成为函数调用t1.operator+()的参数,该调用返回t1与表示t2和t3之和的Time对象的和。最后返回值为t1,t2,t3之和,正是我们想要的结果。可以看出,运算符重载实现运算功能要比函数看起来更加自然一些。

三、重载的限制

多数C++运算符都可以用这样的方式重载。但是没有绝对的自由。主要限制有如下几条:

  1. 重载后的运算符至少有一个操作数是用户定义的类型。这将防止用户为标准类型重载运算符。假如没有这个限制,我们可以将-重载为两个double相加,而不是它们的差,就乱套了。
  2. 使用运算符不能违反运算符原来的句法规则。例如。不能将求模运算符(%)重载成使用一个操作数:% x.同时不能修改运算符的优先级。
  3. 不能创建新的运算符。例如,不能定义operator**()函数来表示求幂。
  4. 不能重载如下运算符:
    • sizeof  sizeof运算符
    • .  成员运算符
    • .* 成员指针运算符
    • :: 作用域解析运算符
    • ?: 条件运算符
    • typeid 一个RTTI运算符
    • const_cast
    • dynamic_cast
    • reinterpret_cast
    • static_cast

  5. 大多数运算符都可以通过成员或者非成员函数重载,但是下面的运算符只能通过成员函数重载

    = 赋值运算符

    () 函数调用运算符

    [] 下表运算符

    -> 通过指针访问类成员的运算符。

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

时间: 2024-08-09 22:01:57

C++学习笔记之运算符重载的相关文章

C++ Primer Plus学习笔记之运算符重载

C++ Primer Plus学习笔记之运算符重载 1,成员函数和友元函数选择的建议 下面我们先看两个例子: 成员函数重载 #include<iostream> using namespace std; class Complex { public: Complex(double r=0,double i=0) { re=r; im=i; } Complex operator+(const Complex& obj); Complex operator!(); void Display

PKU C++程序设计实习 学习笔记4 运算符重载

第四章 运算符重载 4.1 运算符重载的基本概念 1. 运算符 2. 自定义数据类型与运算符重载 C++提供了数据抽象的手段:用户自己定义数据类型 -- 类 ? 调用类的成员函数->操作它的对象 类的成员函数->操作对象时,很不方便 ? 在数学上,两个复数可以直接进行+/-等运算 Vs. 在C++中,直接将+或-用于复数是不允许的 3. 运算符重载 对抽象数据类型也能够直接使用C++提供的运算符 ? 程序更简洁 ? 代码更容易理解 运算符重载 ? 对已有的运算符赋予多重的含义 ? 使同一运算符

C++ Primer 学习笔记_27_操作符重载与转换(2)--++/--运算符重载、!运算符重载、赋值运算符重载 、String类([]、 +、 += 运算符重载)、&gt;&gt;和&lt;&lt;运算符重载

C++ Primer 学习笔记_27_操作符重载与转换(2)--++/--运算符重载.!运算符重载.赋值运算符重载 .String类([]. +. += 运算符重载).>>和<<运算符重载 一.++/--运算符重载 1.前置++运算符重载 成员函数的方式重载,原型为: 函数类型 & operator++(); 友元函数的方式重载,原型为: friend 函数类型 & operator++(类类型 &); 2.后置++运算符重载 成员函数的方式重载,原型为:

C++ Primer 学习笔记_28_操作符重载与转换(3)--成员函数的重载、覆盖与隐藏、类型转换运算符、*运算符重载、-&gt;运算符重载

C++ Primer 学习笔记_28_操作符重载与转换(3)--成员函数的重载.覆盖与隐藏.类型转换运算符.*运算符重载.->运算符重载 一.成员函数的重载.覆盖与隐藏 对于类层次的同名成员函数来说,有三种关系:重载.覆盖和隐藏,理清3种关系,有助于写出高质量的代码. 1.成员函数的重载 重载的概念相对简单,只有在同一类定义中的同名成员函数才存在重载关系,主要特点时函数的参数类型和数目有所不同:但不能出现函数参数的个数和类型均相同,仅仅依靠返回值类型不同来区分的函数,这和普通函数的重载是完全一致

C++ Primer 学习笔记_29_操作符重载与转换(4)--转换构造函数和类型转换运算符归纳、operator new 和 operator delete 实现一个简单内存泄漏跟踪器

C++ Primer 学习笔记_29_操作符重载与转换(4)--转换构造函数和类型转换运算符归纳.operator new 和 operator delete 实现一个简单内存泄漏跟踪器 一.转换构造函数 可以用单个实参来调用的构造函数定义从形参类型到该类型的一个隐式转换.如下: class Integral { public: Integral (int = 0); //转换构造函数 private: int real; }; Integral A = 1; //调用转换构造函数将1转换为In

C++ Primer 学习笔记_26_操作符重载与转换(1)--可重载/不可重载的操作符、成员函数方式重载、友元函数方式重载

C++ Primer 学习笔记_26_操作符重载与转换(1)--可重载/不可重载的操作符.成员函数方式重载.友元函数方式重载 引言: 明智地使用操作符重载可以使类类型的使用像内置类型一样直观! 一.重载的操作符名 像任何其他函数一样,操作符重载函数有一个返回值和一个形参表.形参表必须具有操作符数目相同的形参.比如赋值时二元运算,所以该操作符函数有两个参数:第一个形参对应着左操作数,第二个形参对应右操作数. 大多数操作符可以定义为成员函数或非成员函数.当操作符为成员函数时,它的第一个操作数隐式绑定

C++ Primer笔记12_运算符重载_递增递减运算符_成员访问运算符

1.递增递减运算符 C++语言并不要求递增递减运算符必须是类的成员.但是因为他们改变的正好是所操作对象的状态,所以建议设定为成员函数. 对于递增与递减运算符来说,有前置与后置两个版本,因此,我们应该为类定义两个版本的递增与递减运算符. 问题来了,程序是如何区分前置和后置呢?因为都是++和-- 为了解决这个问题,后置版本的递增递减运算符接受一个额外的(不被使用)int类型的形参.当我们使用后置运算符时,编译器为这个形参提供一个值为0的实参.这个形参唯一的作用就是区分前置和后置运算符函数. 因为不会

PHP学习笔记——3.运算符

目录: PHP学习笔记——1.变量 PHP学习笔记——2.常量 PHP学习笔记——3.运算符 1.算术运算符 + - * / %(求模) %:余数的正负值是由被除数决定的 2.比较运算符 == != > < >= <= === !== ===与!==比较的是变量的值和类型 注:在不同类型进行比较时 PHP会将前一个变量先转换成和后一个变量同一类型,再进行比较 布尔->字符串 true->'1' false->'' 字符串->数字 '123abc456'-&g

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

总结: 1.不能重载的运算符: . 和 .* 和 ?: 和 ::  和 sizeof 和 typeid 2.重载运算符有两种基本选择: 类的成员函数或者友元函数, 建议规则如下: 运算符 建议使用 所有一元运算符 成员函数 = () [] -> 必须是成员函数 += -= /= *= ^= &= != %= >>= <<= , 似乎带等号的都在这里了. 成员函数 所有其它二元运算符, 例如: –,+,*,/ 友元函数 3.前几篇中的实例,现在汇总Person类的程序: