• 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 
    
  • 相关阅读:
    USACO 4.1 Fence Rails
    POJ 1742
    LA 2031
    uva 10564
    poj 3686
    LA 3350
    asp.net MVC 3多语言方案--再次写, 配源码
    使用Log4net记录日志
    在C#用HttpWebRequest中发送GET/HTTP/HTTPS请求
    为什么要使用反射机制
  • 原文地址:https://www.cnblogs.com/mysky007/p/11235313.html
Copyright © 2020-2023  润新知