zoukankan      html  css  js  c++  java
  • C++ 运算符重载

    参考文献:

      《C++程序设计》

      推荐转载博文:https://www.cnblogs.com/xiaokang01/p/9166745.html#_label1

    .............................................................................................................................................................................

      什么是运算符重载?

      运算符重载的本质是一个函数

      

      运算符重载作用:

      

    运算符重载限制:

    1) 并不是所有的运算符都可以重载。能够重载的运算符包括:
    +  -  *  /  %  ^  &  |  ~  !  =  <  >  +=  -=  *=  /=  %=  ^=  &=  |=  <<  >>  <<=  >>=  ==  !=  <=  >=  &&  ||  ++  --  ,  ->*  ->  ()  []  new  new[]  delete  delete[]

    上述运算符中,[]是下标运算符,()是函数调用运算符。自增自减运算符的前置和后置形式都可以重载。长度运算符sizeof、条件运算符: ?、成员选择符.和域解析运算符::不能被重载。

    2) 重载不能改变运算符的优先级和结合性。假设上一节的 complex 类中重载了+号和*号,并且 c1、c2、c3、c4 都是 complex 类的对象,那么下面的语句:

    c4 = c1 + c2 * c3;

    等价于:

    c4 = c1 + ( c2 * c3 );

    乘法的优先级仍然高于加法,并且它们仍然是二元运算符。

    3) 重载不会改变运算符的用法,原有有几个操作数、操作数在左边还是在右边,这些都不会改变。例如~号右边只有一个操作数,+号总是出现在两个操作数之间,重载后也必须如此。

    4) 运算符重载函数不能有默认的参数,否则就改变了运算符操作数的个数,这显然是错误的。

    5) 运算符重载函数既可以作为类的成员函数,也可以作为全局函数。

    将运算符重载函数作为类的成员函数时,二元运算符的参数只有一个,一元运算符不需要参数。之所以少一个参数,是因为这个参数是隐含的。

    例如,上节的 complex 类中重载了加法运算符:

    complex operator+(const complex & A) const;

    当执行:

    c3 = c1 + c2;

    会被转换为:

    c3 = c1.operator+(c2);

    通过 this 指针隐式的访问 c1 的成员变量。

    将运算符重载函数作为全局函数时,二元操作符就需要两个参数,一元操作符需要一个参数,而且其中必须有一个参数是对象,好让编译器区分这是程序员自定义的运算符,防止程序员修改用于内置类型的运算符的性质。

    例如,下面这样是不对的:

    1. int operator + (int a,int b){
    2. return (a-b);
    3. }

    +号原来是对两个数相加,现在企图通过重载使它的作用改为两个数相减, 如果允许这样重载的话,那么表达式4+3的结果是 7 还是 1 呢?显然,这是绝对禁止的。

    如果有两个参数,这两个参数可以都是对象,也可以一个是对象,一个是C ++内置类型的数据,例如:

    1. complex operator+(int a, complex &c){
    2. return complex(a+c.real, c.imag);
    3. }

    它的作用是使一个整数和一个复数相加。

    另外,将运算符重载函数作为全局函数时,一般都需要在类中将该函数声明为友元函数。原因很简单,该函数大部分情况下都需要使用类的 private 成员。

    上节的最后一个例子中,我们在全局范围内重载了+号,并在 complex 类中将运算符重载函数声明为友元函数,因为该函数使用到了 complex 类的 m_real 和 m_imag 两个成员变量,它们都是 private 属性的,默认不能在类的外部访问。

    6) 箭头运算符->、下标运算符[ ]、函数调用运算符( )、赋值运算符=只能以成员函数的形式重载。

      

    运算符重载的方法步骤

    全局函数、类成员函数方法实现运算符重载步骤
    1)要承认操作符重载是一个函数,写出函数名称operator+ ()
    2)根据操作数,写出函数参数
    3)根据业务,完善函数返回值(看函数是返回引用 还是指针 元素),及实现函数业务
     1 #include <iostream>
     2 using namespace std;
     3 
     4 class Complax
     5 {
     6 private:
     7     int a;
     8     int b;
     9     // 重载友元函数 全局函数 操作符重载
    10     friend Complax operator+(Complax &c1, Complax &c2);
    11 public:
    12     Complax(int a = 0, int b = 0)
    13     {
    14         this->a = a;
    15         this->b = b;
    16     }
    17     void printC()
    18     {
    19         cout << "a = " << a << "	b = " << b << endl;
    20     }
    21     // 2成员函数法 实现 - 运算符重载
    22     Complax operator-(Complax &c2)
    23     {
    24 //        this->a -= c2.a;
    25 //        this->b -= c2.b;
    26 //        return *this;  // 这一个会改变c1的值,因为是+=
    27         Complax temp(this->a - c2.a, this->b -c2.b);
    28         return temp;
    29 
    30     }
    31 
    32 };
    33 // 1全局函数法 实现 + 运算符重载
    34 Complax operator+(Complax &c1, Complax &c2)
    35 {
    36     Complax temp(c1.a+c2.a, c1.b+c2.b);
    37     return temp;
    38 }
    39 /*
    40     全局函数,类成员函数方法实现运算符重载步骤
    41     1:要承认运算符重载是一个函数, 写出函数名称
    42     2: 根据操作数,写出函数参数
    43     3:根据业务,完善函数的返回值(看函数返回引用,元素,指针),及实现函数业务
    44 */
    45 int main()
    46 {
    47     Complax c1(1, 2), c2(3, 4);
    48 
    49     // 1全局函数法 实现 - 运算符重载
    50     // Complax operator+(Complax &c1, Complax &c2)
    51     Complax c3 = c1 + c2;
    52     c3.printC();
    53 
    54     // 2成员函数法 实现 - 运算符重载
    55     // Complax operator-(Complax &c2);
    56     Complax c4 = c1 - c2;
    57     c4.printC();
    58 
    59     return 0;
    60 }
    61 
    62 运算符重载的两种方法
    ++重载例子:
     1 #include <iostream>
     2 using namespace std;
     3 
     4 class Complax
     5 {
     6 private:
     7     int a;
     8     int b;
     9     // 1全局函数法 实现 ++ 运算符重载
    10     friend Complax& operator++(Complax &c1);  // 这里是返回一个引用注意,前置++
    11     friend Complax operator++(Complax &c2, int); // 后置++
    12 
    13 public:
    14     Complax(int a = 0, int b = 0)
    15     {
    16         this->a = a;
    17         this->b = b;
    18     }
    19 
    20     // 前置--
    21     // 因为前置返回的是本身,所以返回一个引用
    22     // Complax& operator--(Complax &c1)  这个是写错的,注意错在哪里
    23     Complax& operator--()
    24     {
    25         this->a --;
    26         this->b --;
    27         return *this;
    28     }
    29 
    30     // 后置--  因为后置返回的是一个副本所以不用 返回引用
    31     Complax operator--(int)
    32     {
    33         Complax tem = *this;
    34         this->a--;
    35         this->b--;
    36         return tem;
    37     }
    38 
    39     void printC()
    40     {
    41         cout << "a = " << a << "	b = " << b << endl;
    42     }
    43 };
    44 
    45 
    46 
    47 // 特别注意 只有成员函数才有 this指针
    48 // 1全局函数法 实现 前置++ 运算符重载
    49 Complax& operator++(Complax &c1)
    50 {
    51     c1.a++;
    52     c1.b++;
    53     return c1;
    54 }
    55 // 后置++
    56 Complax operator++(Complax &c2, int) // int防止与前置++重载而加的占位符
    57 {
    58     // 因为后置++是使用, 在让c2++所以要定义一个临时变量
    59     Complax tem = c2;
    60     c2.a++;
    61     c2.b++;
    62     return tem;
    63 }
    64 
    65 
    66 int main()
    67 {
    68     Complax c1(1, 2), c2(30, 40);
    69 
    70     // 1全局函数法 实现 前置++ 运算符重载
    71     //   Complax& operator++(Complax &c1);
    72     ++c1;  // 相当于 operator++(c1);
    73     c1.printC();
    74 
    75     // 2成员函数 实现 前置-- 运算符重载
    76     // 相当于c2.operator--();
    77     --c2;
    78     c2.printC();
    79 
    80     //  1全局函数法 实现 后置++ 运算符重载
    81     // operator++(c2);
    82     c2++;
    83     //  Complax& operator++(Complax &c1);  前置++
    84     //  Complax operator++(Complax &c2, int); // int防止与前置++重载而加的占位符
    85     c2.printC();
    86 
    87     // 2成员函数 实现 后置-- 运算符重载
    88     // 相当于c2.operator--();
    89     // Complax operator--(int) 函数原型
    90     c1--;
    91     c1.printC();
    92 
    93     return 0;
    94 }
    95 
    96 

    深度拷贝:

      1 #include <iostream>
      2 #include <cstring>
      3 #include <cstdlib>
      4 using namespace std;
      5 
      6 class Name
      7 {
      8 public:
      9 
     10     Name (const char *mp)
     11     {
     12         len = strlen(mp);
     13         p = (char *)malloc(sizeof(len+1)); // 注意细节
     14         strcpy(p, mp);
     15 
     16     }
     17 
     18     //Name obj2 = obj1;
     19     // 解决方案:手工编写拷贝构造函数,使用深拷贝
     20     Name (const Name &obj1)
     21     {
     22         len = obj1.len;
     23         p  = (char *)malloc(sizeof(len+1));
     24         strcpy(p, obj1.p);
     25     }
     26 
     27     // 成员函数 =运算符重载  不能写全局函数
     28     Name& operator=(const Name &obj)
     29     {
     30         // 先释放旧的内存  特别注意
     31         if(p != NULL)
     32         {
     33             delete []p;
     34             len = 0;
     35         }
     36         len = obj.len;
     37         p = new char[len+1];
     38         strcpy(p, obj.p);
     39         return *this;
     40     }
     41     ~Name ()
     42     {
     43         cout << "	析构函数" << endl;
     44         if (p != NULL)
     45         {
     46             free(p);
     47             p = NULL;
     48             len = 0;
     49         }
     50     }
     51     void printName()
     52     {
     53         cout <<"	p = " << this->p << "	 len = " << this->len << endl;
     54     }
     55 private:
     56     char *p;
     57     int len;
     58 };
     59 
     60 
     61 // 对象析构的时候会出现,错误
     62 // 调试存在bug
     63 // 析构的时候会出现二次释放
     64 //默认的拷贝构造函数,如果要对指针进行拷贝,则只是浅拷贝,拷贝过后是两个变量指向
     65 //同一段内存,释放拷贝的obj2后,obj1的指针就是垃圾值,在释放就会出错
     66 
     67 void objmain()
     68 {
     69     Name obj1("aaaa");
     70     Name obj2 = obj1;
     71     Name obj3("sfs");
     72 
     73     //  obj3 = obj1;  // 等号操作 c++编译器会对=进行默认的重载(同样会发生二次释放的问题)
     74     // 就需要手动的写 operator= 函数
     75 
     76     cout << "成员函数=重载  ";
     77     obj3 = obj1;
     78     obj3.printName();
     79     // obj3.operator=(const Name & obj1);
     80     // void operator=(const Name &obj)  // 函数声明
     81     // 如果要执行 obj3 = obj2 = obj1; 就需要把void 改成 Name&
     82     {
     83         obj3 = obj2 = obj1;
     84         obj3.printName();
     85         obj2.printName();
     86         obj1.printName();
     87     }
     88 
     89 }
     90 
     91 int main04()
     92 {
     93     objmain();
     94 }
     95 
     96 // 重载 = 运算符注意点
     97 // 1 先把旧的内存释放
     98 // 2 返回一个引用 obj3 = obj1 = obj2;
     99 // 3数据进行拷贝
    100 
    
  • 相关阅读:
    Leetcode Substring with Concatenation of All Words
    Leetcode Divide Two Integers
    Leetcode Edit Distance
    Leetcode Longest Palindromic Substring
    Leetcode Longest Substring Without Repeating Characters
    Leetcode 4Sum
    Leetcode 3Sum Closest
    Leetcode 3Sum
    Leetcode Candy
    Leetcode jump Game II
  • 原文地址:https://www.cnblogs.com/mysky007/p/11235313.html
Copyright © 2011-2022 走看看