第13课 - 操作符重载(=,[], (), ->, ++,&&, ||) - 下

第13课 - 操作符重载 - 下    

    一.类的成员函数作为操作符重载函数

  

  Source Example 1:
        #include <iostream>

        using namespace std;

        class Complex {
            int a;
            int b;
            public:
                Complex(int a = 0, int b = 0)
                {
                    this->a = a;
                    this->b = b;
                }
                
                
                /* 成员函数有一个隐藏的参数this指针,注意第一个参数是隐藏的this指针 */
                Complex operator+ (const Complex& c2 )
                {
                    Complex ret;
                    
                    
                    /* ret.a = this->a + c2.a; */
                    /* ret.b = this->b + c2.b; */
                    
                    ret.a = a + c2.a;
                    ret.b = b + c2.b;
                    
                    return ret;
                }
                
                int GetA()
                {
                    return a;
                }
                
                int GetB()
                {
                    return b;
                }
                friend ostream& operator<< (ostream& out, const Complex& c);
                //friend Complex operator+ (const Complex& c1, const Complex& c2 );
        };
        
        ostream& operator<< (ostream& out, const Complex& c)
                {
                    out<<c.a<<" + "<<c.b<<"i";
                    return out;
                }

        int main()
        {
            Complex c1(1,2);
            Complex c2(1,3);    
            
            /* c1+c2等价于c1.operator+(c2) */
            Complex c3 = c1 + c2;
            
            cout<<c1<<endl;
            cout<<c2<<endl;
            cout<<c3<<endl;
            
            return 0;
        }     

        注意:操作符重载的成员函数左操作符就是this指针,因此会比全局操作符重载函数少一个参数。
        

        1.2 用成员函数重载操作符

            比全局操作符重载函数少一个参数,即左操作数

            不需要使用friend关键字

            

    二.什么时候使用全局操作符重载函数,什么时候用成员操作符重载函数?

        2.1 当无法修改左操作数的类时,使用全局函数进行重载

                例如左移操作符的重载,左操作符为ostream的类,是C++标准库定义的类,不可修改,因此要用全局函数进行重载。

        2.2 =,[],(), ->操作符只能通过成员函数进行重载

        
     

   Source Example 2.2.1:(数组类的改进,[]操作符的重载)
            /* 以前的数组类声明 Array a(10);不像数组,因此我们对[]操作符进行重载 */
            /* 对[]操作符的重载只能使用成员函数 */
            
            /* array.h */
            #ifndef _ARRAY_H_
            #define _ARRAY_H_

            class Array{
                private:
                    int iLength;
                    int *pSpace;
                public:
                    Array(int length);
                    Array(const Array& a);
                    int getLength();
                    ~Array();
                    int& operator[] (int i);
            };

            #endif /* _ARRAY_H_ */
            
            /* array.c */
            #include "array.h"

            Array :: Array(int length)
            {
                iLength = length;
                if (length > 0)
                {
                    pSpace = new int[length];
                }
            }

             int Array :: getLength()
            {
                return iLength;
            }

            Array :: Array(const Array& obj)
            {
                iLength = obj.iLength;
                pSpace = new int[iLength];
                
                for (int i = 0; i < iLength; i++)
                {
                    pSpace[i] = obj.pSpace[i];
                }
            }
            
            /* 此处返回的是必须一个引用
             * 当调用a[i] = i;时,等价于  a.operator[](i) = i;
             * 如果要把一个函数的调用语句作为左值来使用,那么这个函数必须要返回一个引用
             *
             * 由于函数返回值会产生一个临时变量作为返回值的副本,只是一个值。
             * 返回引用会返回变量,因此可以作为左值使用
             */
            int& Array :: operator[] (int i)
            {
                return pSpace[i];
            }
            Array :: ~Array()
            {
                delete[] pSpace;
            }
            
            /* main.cpp */
            
            #include <iostream>
            #include "array.h"
            /* run this program using the console pauser or add your own getch, system("pause") or input loop */

            int main(int argc, char** argv) {
                
                Array a(10);
                
                for (int i = 0; i < 10; i++)
                {
                    a[i] = i;
                }
                
                for (int j = 0; j < a.getLength(); j++)
                {
                    printf ("%d\n", a[j]);
                }
                
                Array a2 = a;
                for (int j = 0; j < a2.getLength(); j++)
                {
                    printf ("%d\n", a2[j]);
                }
                
                return 0;
            }           

        注意: 当调用函数作为左值使用时,返回值必须是一个引用,不能是值!

              由于函数返回值会产生一个临时变量作为返回值的副本,只是一个值。

              返回引用会返回变量,因此可以作为左值使用

              

        

Source Example 2.2.2:(数组类的改进,=操作符的重载)
        /* array.h */
        #ifndef _ARRAY_H_
        #define _ARRAY_H_

        class Array{
            private:
                int iLength;
                int *pSpace;
            public:
                Array(int length);
                Array(const Array& a);
                int getLength();
                ~Array();
                int& operator[] (int i);
                Array& operator= (const Array& obj);
        };

        #endif /* _ARRAY_H_ */
        
        /* array.c */
        #include "array.h"
        #include <iostream>

        Array :: Array(int length)
        {
            iLength = length;
            if (length > 0)
            {
                pSpace = new int[length];
            }
            printf ("pSpace = %08x\n", pSpace);
        }

         int Array :: getLength()
        {
            return iLength;
        }

        Array :: Array(const Array& obj)
        {
            iLength = obj.iLength;
            pSpace = new int[iLength];
            printf ("pSpace = %08x\n", pSpace);
            
            for (int i = 0; i < iLength; i++)
            {
                pSpace[i] = obj.pSpace[i];
            }
        }

        int& Array :: operator[] (int i)
        {
            return pSpace[i];
        }

        
        /*
         * 对=操作符的重载函数,与拷贝构造函数的重载相同,只是需要删除申请pSpace
         * 注意需要返回Array&,因为为了实现连续赋值
         * a3 = a2 = a1;
         * 具体原因与cout的重载原因相同
         * 函数调用作为左值必须要返回引用
          */
        Array& Array :: operator= (const Array& obj)
        {
            delete[] pSpace;
            
            iLength = obj.iLength;
            pSpace = new int[iLength];

            for (int i = 0; i < iLength; i++)
            {
                pSpace[i] = obj.pSpace[i];
            }
            
            /* 返回当前对象 */
            return *this;
        }

        Array :: ~Array()
        {
            delete[] pSpace;
        }
        
        /* main.cpp */
        #include <iostream>
        #include "array.h"
        /* run this program using the console pauser or add your own getch, system("pause") or input loop */

        int main(int argc, char** argv) {
            
            Array a(10);
            /* 定义一个对象a2,初始化没有调用拷贝构造函数 */
            Array a2(1);
            Array a3(2);
            for (int i = 0; i < 10; i++)
            {
                a[i] = i;
            }
            
            for (int j = 0; j < a.getLength(); j++)
            {
                printf ("%d\n", a[j]);
            }
            
            /*
             * 不会调用拷贝构造函数,因为已经初始化了,只是单纯的=赋值
             * 但是=赋值只是进行单纯的复制,导致两个的pSpace只想同一块内存
             * 因此,需要对=操作符进行重载
             */
            a2 = a;
            
            for (int j = 0; j < a2.getLength(); j++)
            {
                printf ("%d\n", a2[j]);
            }
            
            return 0;
        }

    

    Source Example 2.2.3:(数组类的改进,==操作符的重载)
        #ifndef _ARRAY_H_
        #define _ARRAY_H_

        class Array{
            private:
                int iLength;
                int *pSpace;
            public:
                Array(int length);
                Array(const Array& a);
                int getLength();
                ~Array();
                int& operator[] (int i);
                Array& operator= (const Array& obj);
                bool operator== (const Array& obj);
                bool operator!= (const Array& obj);
        };

        #endif /* _ARRAY_H_ */

        
        /* array.c */
        #include "array.h"
        #include <iostream>

        Array :: Array(int length)
        {
            iLength = length;
            if (length > 0)
            {
                pSpace = new int[length];
            }
            printf ("pSpace = %08x\n", pSpace);
        }

         int Array :: getLength()
        {
            return iLength;
        }

        Array :: Array(const Array& obj)
        {
            iLength = obj.iLength;
            pSpace = new int[iLength];
            printf ("pSpace = %08x\n", pSpace);
            
            for (int i = 0; i < iLength; i++)
            {
                pSpace[i] = obj.pSpace[i];
            }
        }

        int& Array :: operator[] (int i)
        {
            return pSpace[i];
        }


        Array& Array :: operator= (const Array& obj)
        {
            delete[] pSpace;
            
            iLength = obj.iLength;
            pSpace = new int[iLength];

            for (int i = 0; i < iLength; i++)
            {
                pSpace[i] = obj.pSpace[i];
            }
            
            return *this;
        }

        /* 重载比较操作符 */
        bool Array :: operator== (const Array& obj)
        {
            bool ret = true;
            
            if (iLength == obj.iLength)
            {
                for (int i = 0; i < iLength; i++)
                {
                    if (pSpace[i] != obj.pSpace[i])
                    {
                        ret = false;
                        break;
                    }
                }
            }
            else
                ret = false;
            
            return ret;
            
        }
        bool Array :: operator!= (const Array& obj)
        {
            return !(*this == obj);
        }
        Array :: ~Array()
        {
            delete[] pSpace;
        }
        
        /* main.cpp */
        #include <iostream>
        #include "array.h"
        /* run this program using the console pauser or add your own getch, system("pause") or input loop */

        int main(int argc, char** argv) {
            
            Array a(10);
            Array a2(1);
            Array a3(2);
            for (int i = 0; i < 10; i++)
            {
                a[i] = i;
            }
            
            for (int j = 0; j < a.getLength(); j++)
            {
                printf ("%d\n", a[j]);
            }
            
            a3 = a2 = a;
            
            if (a2 == a)
            {
                printf ("Hello World!\n");
            }
            for (int j = 0; j < a2.getLength(); j++)
            {
                printf ("%d\n", a2[j]);
            }
            
            return 0;
        }       

        总结:

            a.C++编译器会为每个类提供默认的赋值操作赋

            b.默认的复制操作赋只是进行简单的值复制

            c.类中存在指针成员变量时就需要重载赋值操作符

            

    三.++操作符的重载

        3.1 ++操作符只有一个操作数

        3.2 ++操作符有前缀和有后缀之分

                如何区分++操作符的前缀和后缀呢?

            ++操作符重载也是通过函数重载实现的

                C++中通过一个占位参数来区分前置操作符和后置操作符

                
   

Source Example 3:
            #include <iostream>

            using namespace std;

            class Complex {
                int a;
                int b;
                public:
                    Complex(int a = 0, int b = 0)
                    {
                        this->a = a;
                        this->b = b;
                    }
                    
                    
                    /* 成员函数有一个隐藏的参数this指针 */
                    Complex operator+ (const Complex& c2 )
                    {
                        Complex ret;
                        
                        ret.a = a + c2.a;
                        ret.b = b + c2.b;
                        
                        return ret;
                    }
                    
                    /* 后置++ */
                    Complex operator++ (int);
                    
                    /* 前置++ */
                    Complex& operator++ ();
                    
                    
                    int GetA()
                    {
                        return a;
                    }
                    
                    int GetB()
                    {
                        return b;
                    }
                    friend ostream& operator<< (ostream& out, const Complex& c);
            };

            /* 不能返回引用,因为ret是局部变量 */


            Complex Complex :: operator++ (int)
            {
                Complex ret = *this;
                
                a++;
                b++;
                
                return ret;
            }
            
            /* 前置++操作符比后置++操作符效率高很多 */
            Complex& Complex :: operator++ ()
            {
                a++;
                b++;
                
                return *this;
            }
            ostream& operator<< (ostream& out, const Complex& c)
                    {
                        out<<c.a<<" + "<<c.b<<"i";
                        return out;
                    }

            int main()
            {
                Complex c1(1,2);
                Complex c2(1,3);    
                c1 = c2;
                
                c1++;
                ++c2;
                
                printf ("c1.a = %d, c1.b = %d\n", c1.GetA(), c1.GetB());
                printf ("c2.a = %d, c2.b = %d\n", c2.GetA(), c2.GetB());
                
                return 0;
            }

 

 

 


            

 

 

 

    四.不要重载&&和||操作符

        

 

Source Example 4:
            #include <iostream>

            using namespace std;

            class Test {
                int i;
                public:
                    Test (int i)
                    {
                        this->i = i;    
                    }
                    
                    Test operator+ (const Test& obj)
                    {
                        Test ret = 0;
                        
                        /* 先打印了这一局 */
                        printf ("this->i + obj.i!\n");
                        ret.i = i + obj.i;
                        return ret;
                    }
                    
                    bool operator&& (const Test& obj)
                    {
                        /* 其次打印这一句 */
                        printf ("this->i && obj.i!\n");
                        return (i && obj.i);
                    }
            };

            int main()
            {
                int a1 = 0;
                int a2 = 1;
                
                /* 当a1=0时,(a1+a2)就不会被执行 */
                if (a1 && (a1 + a2))
                {
                    cout<<"Hello World!"<<endl;
                }

                Test t1 = 0;
                Test t2 = 1;
                
                /* 等价于 t1.operator&&(t1.operator+(t2)) */
                /* 因此会先执行t1+t2,与&&操作符的含义并不相同 */
                if (t1 && (t1 + t2))
                {
                    cout<<"Hello World!\n"<<endl;
                }
                return 0;
            }

            输出结果如下
            

            总结:

                &&和||是C++中非常特殊的操作符

                    &&和||内实现了短路规则

                    操作符重载是靠函数重载完成的

                    操作数作为函数参数传递

                    C++中的函数参数都会被求值,无法实现短路规则

    五.小结

        5.1 操作符重载可以直接使用类的成员函数实现

        5.2 =,[],(),->操作符只能通过成员函数进行重载

        5.3 ++操作符通过一个Int参数进行前置与后置的重载

        5.4 C++中不要重载&&和||操作符

                        
        
        

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值