C++核心技术要点《运算符重载》

本文涉及的产品
实时计算 Flink 版,5000CU*H 3个月
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
大数据开发治理平台 DataWorks,不限时长
简介: C++核心技术要点《运算符重载》

1、什么是运算符重载?

(1)运算符重载,就是对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型

  因为在实际中确实有这种需求,例如将两个类对象直接相加,直接比较两个类对象的大小.....等等,因为普通的运算符

  不能完成这种功能,所以在适当的时候对运算符进行重载,能够给我们的编程带来很大的方便。

(2)运算符函数定义的一般格式:

<返回类型说明符> operator<运算符符号>(<参数表>)

{

    <函数体>

}

2、运算符重载的分类:一元运算符重载、二元运算符重载

  一元运算符表示的是这中运算符只需要一个数参与运算,而二元运算符表示这种运算符需要两个数参与运算;例如:两个是相加的

  "+"运算,就是一个二元运算符,两个数相乘的 "*" 运算符也是一个二元运算符;而 "++" "--",还有作为取反的负号运算符 "-"

  等等都是一元运算符。

(1)一元运算符重载,本例子中使用 "-" 和 "++"运算符来演示一元运算符重载的使用,"++"运算符的两种重载方式:前置++、后置++

  按照运算符重载的方式来说,一般分为友元函数重载和成员函数重载两种方式,下面分别用代码进行说明:

 1 #include <iostream>
 2 using namespace std;
 3 
 4 class Coordinate{                   // 定义一个坐标类
 5 public:
 6     Coordinate(int x, int y) : m_iX(x), m_iY(y) { }          // 构造函数
 7     void print(void) { cout << m_iX << ", " << m_iY << endl; }   // 成员函数
 8     Coordinate& operator-(void);                             // "-"  运算符重载
 9     Coordinate& operator++(void);                            // 前置"++" 运算符重载
10     Coordinate operator++(int);                             // 后置"++" 运算符重载  注意返回值类型和上面的不一样,后面再说
11 private:
12     int m_iX;
13     int m_iY;
14 };
15 
16 Coordinate& Coordinate::operator-(void)   // "-" 运算符重载函数定义
17 {
18      this->m_iX = -(this->m_iX); 
19      this->m_iY = -(this->m_iY); 
20      return *this;
21 }
22 
23 Coordinate& Coordinate::operator++(void)  // 前置"++" 运算符重载函数定义
24 {
25     ++(this->m_iX);
26     ++(this->m_iY);
27     return *this;
28 }
29 
30 Coordinate Coordinate::operator++(int)  // 后置"++" 运算符重载函数定义
31 {
32     Coordinate old(*this);  
33     (this->m_iX)++;
34     (this->m_iY)++;
35     return old;
36 }
37 
38 int main(void)
39 {
40     Coordinate coor(2,5);      // 实例化一个Coordinate类对象
41     coor.print();              
42     ++coor;                    // 进行前置 ++ 运算
43     coor.print();
44     coor++;                    // 进行后置 ++ 运算
45     coor.print();
46     -coor;                     // 进行取反运算
47     coor.print();
48     return 0;
49 }

一元运算符的成员函数重载 

  注意到代码中 "++" 运算的前置和后置的申明时区别在于,前置"++"的参数是void,而后置"++"的参数中加上了一个int,注意这个int是必须的(而且只能是int),它是用来说明这    个"++"是作为后置"++"来处理的,所以只要把它理解为一个标记即可。

  Coordinate& operator++(void);       // 前置"++" 运算符重载函数声明

  Coordinate& operator++(int);         // 后置"++" 运算符重载函数声明

 1 #include <iostream>
 2 using namespace std;
 3 
 4 class Coordinate{                     // 定义一个坐标类
 5     friend Coordinate& operator-(Coordinate &c);          // "-"  运算符重载  我们这里的参数使用的是引用,下面会说为什么要用引用
 6     friend Coordinate& operator++(Coordinate &c);         // 前置"++" 运算符重载
 7     friend Coordinate operator++(Coordinate &c, int);     // 后置"++" 运算符重载,同样使用int作为标记,这里的返回值和成员函数重载的返回值是一样的,下面会说
 8 public:
 9     Coordinate(int x, int y) : m_iX(x), m_iY(y) { }          // 构造函数
10     void print(void) { cout << m_iX << ", " << m_iY << endl; }   // 成员函数
11 private:
12     int m_iX;
13     int m_iY;
14 };
15 
16 Coordinate& operator-(Coordinate &c)   // "-" 运算符重载函数定义
17 {
18      c.m_iX = -(c.m_iX); 
19      c.m_iY = -(c.m_iY); 
20      return c;
21 }
22 
23 Coordinate& operator++(Coordinate &c)  // 前置"++" 运算符重载函数定义
24 {
25     ++(c.m_iX);
26     ++(c.m_iX);
27     return c;
28 }
29 
30 Coordinate operator++(Coordinate &c, int)  // 后置"++" 运算符重载函数定义  
31 {
32     Coordinate old(c);  
33     (c.m_iX)++;
34     (c.m_iY)++;
35     return old;
36 }
37 
38 int main(void)
39 {
40     Coordinate coor(2,5);      // 实例化一个Coordinate类对象
41     coor.print();              
42     ++coor;                    // 进行前置 ++ 运算
43     coor.print();
44     coor++;                    // 进行后置 ++ 运算
45     coor.print();
46     -coor;                     // 进行取反运算
47     coor.print();
48     return 0;
49 }

一元运算符的友元函数重载

  注意:成员函数重载和友元函数重载参数类型和返回值类型的区别,不是非得这样做,只是为了符合运算符功能的要求

(2)二元运算符重载:以 "+"、"<<"、"[]" 运算符为例子进行说明

 1 #include <iostream>
 2 using namespace std;
 3 
 4 class Coordinate{                     // 定义一个坐标类
 5     friend ostream &operator<<(ostream &cout, const Coordinate &c);  // 输出运算符 << 重载函数 只能使用友元函数进行重载 后面会说
 6 public:
 7     Coordinate(int x, int y) : m_iX(x), m_iY(y) { }               // 构造函数
 8     void print(void) { cout << m_iX << ", " << m_iY << endl; }    // 成员函数
 9     Coordinate operator+(const Coordinate &c);                    // + 号运算符重载
10     int operator[](int i);                                        // [] 号运算符重载,只能用成员函数进行重载 后面会说
11 private:
12     int m_iX;
13     int m_iY;
14 };
15 
16 ostream &operator<<(ostream &cou, const Coordinate &c)  // 输出运算符 << 重载函数定义
17 {
18     cou << c.m_iX << "," << c.m_iY;
19     return cout;
20 }
21 
22 Coordinate Coordinate::operator+(const Coordinate &c)   // + 号运算符重载函数
23 {
24     Coordinate coor(0,0);
25     coor.m_iX = this->m_iX + c.m_iX;
26     coor.m_iY = this->m_iY + c.m_iY;
27     return coor;
28 }
29 
30 int Coordinate::operator[](int i)        // 索引运算符 [] 重载函数
31 {
32     if (0 == i)
33         return this->m_iX;
34     if (1 == i)
35         return this->m_iY;
36 
37     // 如果传入的参数不是这些,我们应该在下面抛出一个异常,但是我这里没有做,因为我的重点不在这里,在实际的编程中应该加上
38 }
39 
40 int main(void)
41 {
42     Coordinate coor1(2,5);      // 实例化一个Coordinate类对象
43     Coordinate coor2(5,2);
44     Coordinate coor3 = coor1 + coor2;
45     
46     cout << coor3 << endl;
47     cout << coor3[0] << "," << coor3[1] << endl;
48 
49     return 0;
50 }

二元运算符重载

   注意:输出运算符 "<<" 只能通过友元函数进行重载,不能使用成员函数进行重载;索引运算符 "[]" 只能通过成员函数进行重载,不能使用友元函数进行重载。

3、注意事项

(1)返回值类型的问题

  返回值是什么类型运算符重载函数本身并没有限定,也就是说返回值的问题并不会影响编译的问题;因为我们进行运算符重载使之变为方便的同时一定不要对原有

  运算符进行功能性的改变,也就是强调对运算符进行重载一定要有意义,否则没必要。不同的运算符具有不同的功能,所以为了配合这种功能,我们的重载函数的

  返回值也应该有所变化:  Coordinate &operator++()   Coordinate operator++(int)  

  一个返回的是引用类型,一个返回的是类类型,为什么这样做,其实和 前置++ 和 后置++ 本身的运算功能有关。

(2)运算符重载的本质。

  运算符重载本质就是函数重载,对于运算符的成员函数重载,因为成员函数会默认带上一个this指针,而友元函数没有this指针

#include <iostream>
using namespace std;

class Coordinate{                     // 定义一个坐标类
    friend Coordinate operator+(const Coordinate &c1, const Coordinate &c2);
    ..........
public:
    Coordinate operator+(const Coordinate &c);                    // + 号运算符重载
    ..........
private:
    int m_iX;
    int m_iY;
};

......................   // 省略了重载函数定义

int main(void)
{
    Coordinate coor1(1,2);
    Coordinate coor2(3,4);
    Coordinate coor3 = coor1 + coor2;   //对于成员函数其实就是调用了 operator+(coor2),而对于友元函数即时调用了 operator+(coor1, coor2)
    return 0;
}

    注意:成员函数中的默认this指针总是作为第一个参数的,而这个参数的位置又直接和运算时的操作数的位置又是先联系在一起的;这是规定的,所以这也就是导致了有些运算符的重载       函数只能是友元函数,而有些运算符的重载函数只能是成员函数。

(3)对于运算符的友元重载函数来,他的参数中至少有一个类类型参数(类类型和引用)

  例如对于我们的运算符的友元重载函数: friend Coordinate operator+(const Coordinate *c1, const Coordinate *c2);   // 这样是错误的,因为没有一个参数是类类型参                                                                                                                 // 数

  friend Coordinate operator+(const Coordinate &c1, const Coordinate *c2);       // 这样是正确的,因为至少有一个参数是类类型

  friend Coordinate operator++(Coordinate &c);          // 这样是正确的

  friend Coordinate operator++(Coordinate *c);          // 这样是错误的

(3)只能重载允许重载的运算符,不能创造新的运算符

(4)重载之后的功能应该与原来的运算符在功能上一致,只是适应了更多的数据类型。

(3)对于有些运算符不能同时定义友元重载函数和成员重载函数,而有些运算符可以同时定义友元函数和成员函数。

对于这个问题,网上有人说是C++本身规定的,=、[]、()和->四种运算符只能被重载为类的非静态成员函数。

1 #include <iostream>
 2 using namespace std;
 3 
 4 class Coordinate{
 5     friend Coordinate operator+(const Coordinate &c1, const Coordinate &c2); // "+" 运算符的友元函数重载
 6     friend Coordinate &operator++(Coordinate &c);                            // 前置"++" 运算符的友元函数重载
 7 public:
 8     Coordinate(int x, int y) : m_iX(x), m_iY(y) {  }
 9     void print(void) { cout << m_iX << "," << m_iY << endl; }
10     Coordinate operator+(const Coordinate &c);                 // "+" 运算符的成员函数重载
11     Coordinate &operator++(void);                              // 前置"++" 运算符的成员函数重载
12 private:
13     int m_iX;
14     int m_iY;
15 };
16 
17 Coordinate operator+(const Coordinate &c1, const Coordinate &c2)
18 {
19     Coordinate temp(0,0);
20     temp.m_iX = c1.m_iX + c2.m_iX;
21     temp.m_iY = c1.m_iY + c2.m_iY;
22     return temp;
23 }
24 
25 Coordinate Coordinate::operator+(const Coordinate &c)
26 {
27     Coordinate temp(0, 0);
28     temp.m_iX = this->m_iX + c.m_iX;
29     temp.m_iY = this->m_iY + c.m_iY;
30     return temp;
31 }
32 
33 Coordinate &operator++(Coordinate &c)
34 {
35     ++c.m_iX;
36     ++c.m_iY;
37     return c;
38 }
39 
40 Coordinate &Coordinate::operator++(void)
41 {
42     ++(this->m_iX);
43     ++(this->m_iY);
44     return *this;
45 }
46 
47 int main(void)
48 {
49     Coordinate coor1(1, 2);
50     Coordinate coor2(3, 4);
51     Coordinate coor3 = coor1 + coor2;      // 在友元重载函数和成员重载函数同时存在的情况下执行 "+" 运算没有问题    
52 //    ++coor3;                               // 在友元重载函数和成员重载函数同时存在的情况下执行 前置"++" 运算,编译不能通过
53     coor3.print();
54     return 0;
55 }

Code

ad95227b62cc858f445b67ffdb331b69_944893-20161031191103221-700805773.png

  从上面的代码中看出,当同时存在 “+” 运算符的友元函数重载和成员函数重载时,程序编译没有问题,而且优先执行的是成员函数重载方式的运算符;而对于 前置"++" 运算符,同时存     在友元函数重载和成员函数重载时,执行 ++coor3; 却导致编译报错,显示有多个运算符与操作数匹配,操作不明确。 对于这个我实在是有点理解不了。

(4)主要是用于面向对象之间的重载。

(5)当需要重载运算符可以使用友元函数和成员函数时,应选择重载为成员函数。

  因为对于友元函数来说,之前说过,在能够不需要使用的情况下,尽量不要使用。

(6)重载函数的参数不能超过2个。

相关文章
|
19天前
|
编译器 C++
C++进阶之路:何为运算符重载、赋值运算符重载与前后置++重载(类与对象_中篇)
C++进阶之路:何为运算符重载、赋值运算符重载与前后置++重载(类与对象_中篇)
26 1
|
25天前
|
C++
C++中类的接口与实现分离的技术性探讨
C++中类的接口与实现分离的技术性探讨
30 1
|
25天前
|
程序员 编译器 C++
C++中的运算符重载(Operator Overloading)
C++中的运算符重载(Operator Overloading)
29 1
|
25天前
|
C++
C++代码的可读性与可维护性:技术探讨与实践
C++代码的可读性与可维护性:技术探讨与实践
21 1
|
17小时前
|
存储 编译器 C++
【C++】:拷贝构造函数和赋值运算符重载
【C++】:拷贝构造函数和赋值运算符重载
5 1
|
13天前
|
C++
C++核心技术要点《友元函数,友元类》
C++核心技术要点《友元函数,友元类》
20 3
|
13天前
|
C++
C++核心技术要点《异常处理详解》
C++核心技术要点《try-throw-catch异常处理详解》
16 2
|
13天前
|
C++
c++语言核心技术要点,《运行时类型识别RTTI》
c++语言核心技术要点,《运行时类型识别RTTI》
17 2
|
14天前
|
存储 算法 安全
用C++打造极致高效的框架:技术探索与实践
本文探讨了如何使用C++构建高性能框架。C++凭借其高性能、灵活性和跨平台性成为框架开发的理想选择。关键技术和实践包括:内存管理优化(如智能指针和自定义内存池)、并发编程(利用C++的并发工具)、模板与泛型编程以提高代码复用性,以及性能分析和优化。在实践中,应注意代码简洁性、遵循最佳实践、错误处理和充分测试。随着技术发展,不断提升对框架性能的要求,持续学习是提升C++框架开发能力的关键。
24 1
|
25天前
|
C++
C++中使用namespace关键字定义和访问命名空间的技术性探讨
C++中使用namespace关键字定义和访问命名空间的技术性探讨
16 3