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

本文涉及的产品
实时计算 Flink 版,5000CU*H 3个月
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
实时数仓Hologres,5000CU*H 100GB 3个月
简介: 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个。

相关文章
|
2月前
|
存储 算法 C++
C++提高篇:泛型编程和STL技术详解,探讨C++更深层的使用
文章详细探讨了C++中的泛型编程与STL技术,重点讲解了如何使用模板来创建通用的函数和类,以及模板在提高代码复用性和灵活性方面的作用。
50 2
C++提高篇:泛型编程和STL技术详解,探讨C++更深层的使用
|
5月前
|
存储 分布式数据库 API
技术好文:VisualC++查看文件被哪个进程占用
技术好文:VisualC++查看文件被哪个进程占用
|
2月前
|
C++
C++(十五) 运算符重载
C++中的运算符重载允许对已有运算符的功能进行重新定义,从而扩展语言功能、简化代码并提升效率。重载遵循特定语法,如 `friend 类名 operator 运算符(参数)`。重载时需注意不可新增或改变运算符数量、语义、优先级、结合性和返回类型。常见示例包括双目运算符 `+=` 和单目运算符 `-` 及 `++`。输入输出流运算符 `&lt;&lt;` 和 `&gt;&gt;` 也可重载。部分运算符只能作为成员函数重载。
|
3月前
|
人工智能 Anolis
聚焦C++20 最新标准!技术 Workshop 精彩亮点一览 | 2024 龙蜥大会
多场技术 Workshop、多位领域专家亲自授课,分享独家洞察与宝贵经验。
|
3月前
|
算法 C# 开发工具
《黑神话:悟空》背后的编程语言揭秘——超越C++的多元技术融合
【8月更文挑战第27天】在游戏开发领域,一款游戏的成功往往离不开其背后强大的技术支持和编程语言的精妙运用。《黑神话:悟空》作为备受瞩目的国产单机动作游戏,其开发过程不仅涉及了多种编程语言,更是一次技术创新的集中展现。然而,当我们深入探讨其开发语言时,会发现它并非仅依赖于单一的C++,而是融合了多种编程语言的优势,共同铸就了这款游戏的辉煌。
253 0
|
5月前
|
存储 编译器 C++
【C++】:拷贝构造函数和赋值运算符重载
【C++】:拷贝构造函数和赋值运算符重载
30 1
|
5月前
|
C++
C++核心技术要点《友元函数,友元类》
C++核心技术要点《友元函数,友元类》
54 3
|
4月前
|
自然语言处理 程序员 C++
C++基础知识(五:运算符重载)
运算符重载是C++中的一项强大特性,它允许程序员为自定义类型(如类或结构体)重新定义标准运算符的行为,使得这些运算符能够适用于自定义类型的操作。这样做可以增强代码的可读性和表达力,使得代码更接近自然语言,同时保持了面向对象编程的封装性。
|
4月前
|
Java 程序员 C++
|
4月前
|
编译器 C++
【C++】详解运算符重载,赋值运算符重载,++运算符重载
【C++】详解运算符重载,赋值运算符重载,++运算符重载