zoukankan      html  css  js  c++  java
  • 【c++】重载操作符

    目录

    1. 输入和输出操作符
    2. 算术操作符和关系操作符
    3. 下标操作符
    4. 自加、自减操作符
    5. 成员访问操作符

    1  输入和输出操作符

    1.1 输出操作符

    1.1.1 示例

    #include <iostream>
    #include <string>
    using namespace std;
    
    class A
    {
        friend ostream& operator<<(ostream& out, const A& a);
        public:
            A(const string &s = "", int v = 0) : ss(s), val(v) {} //构造函数带默认参数
        private:
            int val;
            string ss;
    };
    
    ostream& operator<<(ostream& out, const A& a)
    {
        out << "a.ss:" << a.ss << " " << "a.val:" << a.val;
        return out;
    }
    
    int main()
    {
        A a("hello", 23);
        cout << a << endl;
        A b;
        cout << b << endl;
    }

    结果

    1.1.2 说明

    1)IO操作必须为非成员函数

    原因:I/O操作的接口返回的是ostream&对象(只有返回左值,这样才可以连续的输出,例如cout << a << b)。自定义的输出操作符应该与其相似。如果将其定义为成员函数(有个首默认参数this,即指向自己的指针),左操作数只能是该类型的对象,则没法办到。例如:Sales_item; item << cout; 与常规定义相反,因此只能为非成员函数。

    2)因为要访问指定类的私有成员,所以在该类中声明输出操作符为友员函数。

    3)第一个形参必须为引用。因为I/O对象不可以复制。同理返回值必须为一个引用。

    4)第一个形参不可以为const,因为写入到流会改变其值。

    5)第二个为引用,这样可以避免复制。参数可以为const,可以接收const对象和非const对象;否则,如果为非const,则只能接收非coust对象。一般为const,毕竟只是输出而已,不改变对象。

    1.2 输入操作符

    1.2.1 示例

    #include <iostream>
    #include <string>
    using namespace std;
    
    class A
    {
        friend ostream& operator<<(ostream& out, const A& a);
        friend istream& operator>>(istream& in, A& a);
        public:
            A(const string &s = "", int v = 0) : ss(s), val(v) {}
        private:
            int val;
            string ss;
    };
    
    ostream& operator<<(ostream& out, const A& a)
    {
        out << "a.ss:" << a.ss << " " << "a.val:" << a.val;
        return out;
    }
    istream& operator>>(istream& in, A& a)
    {
        in >> a.ss >> a.val;
        if(in)
        {
            cout << "Input right" << endl;
        }
        else
        {
            cout << "in.fail:" << in.fail() << endl;
            cout << "input wrong!" << endl;
        }
        return in; 
    }
    
    int main()
    {
        A a("hello", 23);
        cout << a << endl;
        A b;
        cin >> b;
        cout << b << endl;
    }

    结果

    1.2.2 说明

    1)输入与输出操作符的重要区别:输入操作符必须处理错误和文件结束的可能性。

    2)输入如果有多个值的话,如果一个数错了,整个输入对象就错了(False),从示例中可以看出,前边赋值正确的已经生效了,后边的用了默认值,可以这样设计:如果输入错误,将整个对象复位,恢复到最初的状态,例:

    #include <iostream>
    #include <string>
    using namespace std;
    
    class A
    {
        friend ostream& operator<<(ostream& out, const A& a);
        friend istream& operator>>(istream& in, A& a);
        public:
            A(const string &s = "", int v = 0) : ss(s), val(v) {}
            A(const A& a)
            {
                ss = a.ss;
                val = a.val;
            } 
    
            A& operator=(const A& a) 
            {
                if(this != &a)
                {
                    ss = a.ss;
                    val = a.val;
                    return *this;
                }
            }
        private:
            int val;
            string ss;
    };
    
    ostream& operator<<(ostream& out, const A& a)
    {
        out << "a.ss:" << a.ss << " " << "a.val:" << a.val;
        return out;
    }
    istream& operator>>(istream& in, A& a)
    {
        in >> a.ss >> a.val;
        if(in)
        {
            cout << "Input right" << endl;
        }
        else
        {
            cout << "in.fail:" << in.fail() << endl;
            cout << "input wrong!" << endl;
            a = A();
        }
        return in; 
    }
    
    int main()
    {
        A a("hello", 23);
        cout << a << endl;
        A b;
        b = a;
        cin >> b;
        cout << b << endl;
    }
    View Code

    2 算术操作符和关系操作符

    2.1 相等操作符

    2.1.1 示例

    #include <iostream>
    #include <string>
    using namespace std;
    
    class A
    {
        friend bool operator==(const A& a, const A& b);
        friend bool operator!=(const A& a, const A& b);
        public:
            A(string s = "", int v = 0) : ss(s), val(v) {}
        private:
            string ss;
            int val;
    };
    
    bool operator==(const A& a, const A& b)
    {
        return a.ss == b.ss && a.val == b.val;
    }
    
    bool operator!=(const A& a, const A& b)
    {
        return !(a == b);
    }
    
    int main()
    {
        A a("hello", 53);
        A b("hello", 54);
        A c("hello", 54);
        cout << "a == b?:" << (a == b) << endl;
        cout << "a != b?:" << (a != b) << endl;
        cout << "b == c?:" << (b == c) << endl;
        cout << "b != c?:" << (b != c) << endl;
    }

    结果

    2.1.2说明

    1)定义了类的==,对应的应该定义!=

    2.2 关系操作符

    2.2.1 示例

    #include <iostream>
    #include <string>
    using namespace std;
    
    class A
    {
        friend bool operator<(const A& a, const A& b);
        public:
            A(string s = "", int v = 0) : ss(s), val(v) {}
        private:
            string ss;
            int val;
    };
    
    bool operator<(const A& a, const A& b)
    {
        return (a.val < b.val);
    }
    
    int main()
    {
        A a("hello", 53);
        A b("he", 55);
        cout << "a < b?:" << (a < b) << endl;
    }

    结果

    2.2.2 说明

    1)定义了相等操作符,一般也定义关系操作符

    2)关系操作符要根据具体的含义定义

    2.3 赋值操作符

    2.3.1 示例

    #include <iostream>
    #include <string>
    using namespace std;
    
    class A
    {
        friend ostream& operator<<(ostream& out, const A& a);
        public:
            A(string s = "", int v = 0) : ss(s), val(v) {}
            A& operator=(const A& a);
        private:
            string ss;
            int val;
    };
    
    ostream& operator<<(ostream &out, const A& a)
    {
        out << "a.ss:" << a.ss << " " << "a.val:" << a.val;
    }
    
    A& A::operator=(const A& a)
    {
        if(this != &a)
        {
            ss = a.ss;
            val = a.val;
        }
        return *this;
    }
    
    
    int main()
    {
        A a("hello", 53);
        A b("he", 55);
        cout << b << endl;
        b = a;
        cout << b << endl;
    }

    2.3.2 说明

    1) 复制操作符完成对同类对象的赋值,参数一般为对类类型的const引用。

    2)如果没有,编译器会自动合成一个,类的赋值操作符一定为类的成员变量,以便编译器是否需要自己合成一个。

    3)返回值必须为*this的引用,这样就不需要创建和撤销结果的临时副本。同理的有复合赋值操作符,例如

    #include <iostream>
    #include <string>
    using namespace std;
    
    class A
    {
        friend ostream& operator<<(ostream& out, const A& a);
        public:
            A(string s = "", int v = 0) : ss(s), val(v) {}
            A& operator+=(const A &);
        private:
            string ss;
            int val;
    };
    
    ostream& operator<<(ostream &out, const A& a)
    {
        out << "a.ss:" << a.ss << " " << "a.val:" << a.val;
    }
    
    A& A::operator+=(const A& a)
    {
        val += a.val;
        return *this;
    }
    
    int main()
    {
        A a("hello", 53);
        A b("he", 55);
        a += b;
        cout << a << endl;
    }
    View Code

    结果

    2.4 加法操作符

    2.4.1 示例

    #include <iostream>
    #include <string>
    using namespace std;
    
    class A
    {
        friend ostream& operator<<(ostream& out, const A& a);
        friend A operator+(const A &a ,const A &b);
        public:
            A(string s = "", int v = 0) : ss(s), val(v) {}
            A(const A&);
            A& operator+=(const A &);
        private:
            string ss;
            int val;
    };
    
    A::A(const A& a) 
    {
        ss = a.ss;
        val = a.val;
    }
    
    ostream& operator<<(ostream &out, const A& a)
    {
        out << "a.ss:" << a.ss << " " << "a.val:" << a.val;
    }
    
    A operator+(const A &a ,const A &b)
    {
        A tmp(a);
        tmp += b;
        return tmp;
    }
    
    A& A::operator+=(const A& a)
    {
        val += a.val;
        return *this;
    }
    
    int main()
    {
        A a("hello", 53);
        A b("he", 55);
        a += b;
        cout << a + b << endl;
    }

    2.4.2 说明

    1) 根据复合操作符(如+=)实现算术操作符(如+),比其他方式更有效

    3 下标操作符

    3.1.1 示例

    #include <iostream>
    #include <string>
    using namespace std;
    
    class A
    {
        friend ostream& operator<<(ostream& out, const A& a);
        public:
            A(string s = "", int v = 0) : ss(s), val(v) {}
            char& operator[](const size_t);
            const& char operator[](const size_t) const;
        private:
            string ss;
            int val;
    };
    
    ostream& operator<<(ostream& out, const A& a)
    {
        out << "a.val:" << a.val << "  " << "a.ss:" << a.ss;
        return out;
    }
    
    char& A::operator[](const size_t index)
    {
        return ss[index];
    }
    
    const char& A::operator[](const size_t index) const
    {
        return ss[index];
    }
    
    
    int main()
    {
        A a("hello", 53);
        cout << a[2] << endl;
    }

    结果

    e

    3.1.2 说明

    1) 下标操作必须为函数成员,因为传递一个参数,还需要另一个指向自己的指针参数,正好函数成员的this可以胜任。

    2) 类定义下标时,一般定义两个版本:一个为非const成员,并返回非const引用; 另一个为const成员,并返回const引用。这样应用与const对象时,返回值应为const引用,不能用作赋值的目标。

    4 自加、自减操作符

    4.1 前置自加、自减操作符

    4.1.1 示例

    #include <iostream>
    #include <string>
    using namespace std;
    
    class A
    {
        friend ostream& operator<<(ostream& out, const A& a);
        public:
            A(string s = "", int v = 0) : ss(s), val(v) {}
            A& operator++();
            A& operator--();
        private:
            string ss;
            int val;
    };
    
    ostream& operator<<(ostream& out, const A& a)
    {
        out << "a.val:" << a.val << "  " << "a.ss:" << a.ss;
        return out;
    }
    
    A& A::operator++()
    {
        ++val;
        return *this;
    }
    
    A& A::operator--()
    {
        --val;
        return *this;
    }
    
    int main()
    {
        A a("hello", 53);
        cout << a << endl;
        ++a;
        cout << a << endl;
        ++a;
        cout << a << endl;
        --a;
        cout << a << endl;
    }

    结果

    4.2 后置自加、自减操作符

    4.2.1 示例

    #include <iostream>
    #include <string>
    using namespace std;
    
    class A
    {
        friend ostream& operator<<(ostream& out, const A& a);
        public:
            A(string s = "", int v = 0) : ss(s), val(v) {}
            A& operator++();
            A& operator--();
            A operator++(int);
            A operator--(int);
        private:
            string ss;
            int val;
    };
    
    ostream& operator<<(ostream& out, const A& a)
    {
        out << "a.val:" << a.val << "  " << "a.ss:" << a.ss;
        return out;
    }
    
    A& A::operator++()
    {
        ++val;
        return *this;
    }
    
    A& A::operator--()
    {
        --val;
        return *this;
    }
    A A::operator++(int)
    {
        A tmp(*this);
        ++(*this);
        return tmp;
    }
    
    A A::operator--(int)
    {
        A tmp(*this);
        --(*this);
        return tmp;
    }
    
    int main()
    {
        A a("hello", 53);
        cout << a << endl;
        ++a;
        cout << a << endl;
        ++a;
        cout << a << endl;
        cout << "hello" << endl;
        cout << (a--) << endl;;
        cout << a << endl;
    }

    4.2.2 说明

    1)为了区分与前置自加、自减操作符的区别,后置需要接受一个而外的(无用的)的int型形参。使用后缀式操作符时,编译器提供0作为这个形参的实参,其唯一目的是为了区别前缀、后缀。

    2)a++返回的是加之前的状态,因此,定义一个局部对象,保存(*this),最后返回这个局部变量的备份(注意不可以为引用,毕竟是局部的)。

    5. 成员访问操作符

    5.1.1 示例

    #include <iostream>
    #include <string>
    using namespace std;
    class B
    {
        public:
            void print_B() { cout << "hello !!" << endl; }
    };
    class U_Ptr 
    {
        friend class HasPtr;
        B* ip;
        size_t use;
        U_Ptr(B *p) : ip(p), use(1) {}
        ~U_Ptr() { delete ip; }
    };
    
    class HasPtr
    {
        public:
            HasPtr(B *p, int i) : ptr(new U_Ptr(p)), val(i) {}
            HasPtr(const HasPtr &orig) : ptr(orig.ptr), val(orig.val) { ++ptr->use; }
            HasPtr& operator=(const HasPtr &orig);
            ~HasPtr() { if(--ptr->use == 0) delete ptr; }
            B& operator*() { return *ptr->ip; }
            B* operator->() { return ptr->ip; }
        private:
            U_Ptr *ptr;
            int val;
    };
    
    HasPtr& HasPtr::operator=(const HasPtr &orig)
    {
        if(this != &orig)
        {
            ptr = orig.ptr;
            val = orig.val;
            ++(ptr->use);
        }
        return *this;
    }
    
    int main()
    {
        HasPtr hasptr1(new B, 23);
        HasPtr hasptr2(hasptr1);
        *hasptr1;
        hasptr1->print_B();
    }

    结果

    hello!!

    5.1.2 说明

    1) 箭头必须定义为成员函数, 解引用不要求定义为成员,但是可以作为成员。

    2) 解引用和箭头操作常用在实现智能指针的类中。

  • 相关阅读:
    诡异的命名空间问题
    如何为自定义属性提供表达式绑定支持
    为SSIS编写自定义数据流组件(DataFlow Component)之进阶篇:自定义编辑器
    SSAS : 外围应用配置器
    SSAS : 数据访问接口整理汇总
    SSAS : ADOMDConnection.ConnectionString的参数列表
    SSIS中的字符映射表转换组件
    SSAS: Discover 何处寻? 一切尽在GetSchemaDataSet
    为SSIS编写简单的同步转换组件
    如何在同步转换组件中增加输出列
  • 原文地址:https://www.cnblogs.com/kaituorensheng/p/3505115.html
Copyright © 2011-2022 走看看