zoukankan      html  css  js  c++  java
  • C++primer 阅读点滴记录(三)

    14章 操作符重载和转换

       重载操作符是具有特殊名称的函数:保留字operator后接需要定义的操作符符号。

      1、重载的操作符名:

        + – * / % ^ & | ~ ! , = <  >  <= >= ++ – << >> == != && ||等

       不能重载的操作符:     ::    *  . ?

       2、 重载操作符 必须具有一个类类型操作数。

             int operator+(int,int) ;//error : cannot defined built-in operator for ints

      3、优先级和结合性是固定的

      4、不再具备短路求值特性(重载&&和||不是一种好的做法)

      5、类成员和非成员

          大多数重载操作符可以定义为普通非成员函数或类的成员函数。

          注解: 作为类成员的冲在函数,其形参看起来比操作数数目少1。作为成员函数的操作符有一个隐含的this形参,限定为第一个操作数。

    ps: 一般将算术和关系运算定义为非成员函数,而将赋值操作符定义为成员。

    // member binary operator: left-hand operand bound to implicit this pointer
    Sales_item& Sales_item::operator+=(const Sales_item&);
    
    //nonmember binary operator: must declare a parameter for each operand
    
    Sales_item operator+(const Sales_item&,const Sales_item&);

    6、操作符重载和友元关系

      操作符定义为非成员函数时,通常必须将它们设置为所操作类的友元。

    最佳实践:当一个重载操作符的含义不明显时,给操作取一个名字更好。对于很少用的操作使用命名函数通常比用操作符更好。如果不是普通操作,没必要为简洁而使用操作符。

    输出操作符

    std::ostream& operator<<(std::ostream& os,const Sales_item& s){
        os<<s.isbn<<"	"<<s.units_sold<<"	"
            <<s.revenue<<"	"<<s.avg_price();
        return os;
    }

    最佳实践

         一般而言,输出操作符应输出对象的内容,进行最小限度的格式化,它们不应该输出换行符。

        IO操作符必须为非成员函数

    friend std::istream& operator>>(std::istream&,Sales_item&);
        friend std::ostream& operator<<(std::ostream&,const Sales_item&);

    输入操作符:

      注意: 输入操作的第二形参必须为非const引用,而且输入操作符必须处理错误和文件借宿的可能。

    std::istream& operator>>(std::istream& in,Sales_item& s){
        double price;
        in>>s.isbn>>s.units_sold>>price;
        if(in)
            s.revenue = s.units_sold * price;
        else
            s = Sales_item();//input failed, reset object to default state
        return in;
    }

    算术操作符和关系操作符

    Sales_item& Sales_item::operator+=(const Sales_item& rhs){
        if (isbn == rhs.isbn){
            units_sold += rhs.units_sold;
            revenue += rhs.revenue;
        }
        return *this;
    }
    
    Sales_item operator+(const Sales_item& s1,const Sales_item& s2){
        Sales_item ret(s1);
        ret += s2;//use operator+= 
        return ret;
    }
    
    inline bool
        operator==(const Sales_item& lhs,const Sales_item& rhs){
            return lhs.units_sold == rhs.units_sold &&
                lhs.revenue == rhs.revenue &&
                lhs.same_isbn(rhs);
    }
    
    inline bool
        operator!=(const Sales_item& lhs,const Sales_item& rhs){
            return !(lhs==rhs);//!= defined interm of operator==
    }

    最佳实践

       为了与内置操作符保持一致,加法返回一个右值,而不是一个引用。

       既定义了算术操作又定义了相关复合赋值操作的类,一般应使用复合操作实现算术操作符。

       赋值操作符必须返回*this的引用

    下标操作符: 

    #ifndef FOO_H
    #define FOO_H
    
    #include <vector>
    using std::vector;
    
    class Foo{
    public:
        int &operator[](const size_t);
        const int &operator[](const size_t);
    private:
        vector<int> data;
    };
    
    int& Foo::operator [](const size_t index){
        return data[index];//no range checking on index
    }
    
    const int& Foo::operator [](const size_t index){
        return data[index];//no range checking on index
    }
    
    #endif // !FOO_H
    最佳实践:

         下标操作符必须定义为类成员函数

         类定义下标操作符时,一般需要定义两个版本,一个为非const成员并返回引用,另一个为const成员并返回const引用。

    成员访问操作符(*  –>)

      注解: 箭头操作符必须定义为类成员函数,解引用操作符不要定义为成员,但将它作为成员一般也是正确的。

      1、构建更安全的指针

    #ifndef SCRPTR_H
    #define SCRPTR_H
    #include "Person.h"
    #include <iostream>
    
    class ScrPtr{
        friend class ScreenPtr;
        Screen *sp;
        size_t use;
        ScrPtr(Screen *p):sp(p),use(1){}
        ~ScrPtr(){delete sp;}
    };
    
    class ScreenPtr{
    public:
        ScreenPtr(Screen* p):ptr(new ScrPtr(p)){}
        ScreenPtr(const ScreenPtr& orig):ptr(orig.ptr){++ptr->use;}
        ScreenPtr& operator=(const ScreenPtr&);
        ~ScreenPtr(){
            if(--ptr->use = 0)
                delete ptr;
        }
        //两个版本 const和非const
        Screen& operator*(){return *ptr->sp;}
        Screen* operator->(){return ptr->sp;}
        const Screen& operator*()const{return *ptr->sp;}
        const Screen* operator->()const{return ptr->sp;}
    private:
        ScrPtr *ptr;
    };
    
    ScreenPtr& ScreenPtr::operator=(const ScreenPtr& rhs){
        ++rhs.ptr->use;
        if(--ptr->use == 0)
            delete ptr;
        ptr = rhs.ptr;
        return *this;//注意赋值 复合赋值操作符必须返回*this
    }
    
    void scrptrTest(){
        Screen myscreen;
        ScreenPtr p(&myscreen);
        p->display(std::cout);
    }
    
    
    #endif // !SCRPTR_H

    注解:重载箭头操作符必须返回指向类类型的指针,或者返回定义了自己箭头操作符的类类型对象。

      自增操作符和自减操作符

    #ifndef CHECKED_PTR_H
    #define CHECKED_PTR_H
    
    /*
     * smart pointer: Checks access to elements throws an out_of_range
     *                  exception if attempt to access a nonexistent element
     *
     * user allocate and free the array
     */
    
    class CheckedPtr{
    public:
        CheckedPtr(int* b, int* e):beg(b),end(e),curr(b){}
        //prefix operators
        CheckedPtr& operator++();
        CheckedPtr& operator--();
        //postfix operators
        CheckedPtr operator++(int);
        CheckedPtr operator--(int);
    private:
        int* beg;
        int* end;
        int* curr;
    };
    
    CheckedPtr& CheckedPtr::operator ++(){
        if(curr == end)
            throw out_of_range ("increment past the end of CheckedPtr");
        ++curr;
        return *this;
    }
    
    CheckedPtr& CheckedPtr::operator --(){
        if(curr == beg)
            throw out_of_range("decrement past the beginning of CheckedPtr");
        --curr;
        return *this;
    }
    
    CheckedPtr CheckedPtr::operator ++(int){
        CheckedPtr ret(*this);
        ++*this;
        return ret;
    }
    
    CheckedPtr CheckedPtr::operator --(int){
        CheckedPtr ret(*this);
        --*this;
        return ret;
    }
    #endif // !CHECKED_PTR_H

    调用操作符和函数对象

    struct absInt
    {
        int operator()(int val){
            return val < 0? -val : val;
        }
    };
    
    void absInt_test(){
        int i = -32;
        absInt absObj;
    
        using int ui = absObj(i);
    }

    注解:函数调用操作符必须声明为成员函数。一个类可以定义函数调用操作符的多个版本。有形参的数目或类型加以区别。

  • 相关阅读:
    1.27
    1.25
    Representation Learning with Contrastive Predictive Coding
    Learning a Similarity Metric Discriminatively, with Application to Face Verification
    噪声对比估计(负样本采样)
    Certified Adversarial Robustness via Randomized Smoothing
    Certified Robustness to Adversarial Examples with Differential Privacy
    Dynamic Routing Between Capsules
    Defending Adversarial Attacks by Correcting logits
    Visualizing Data using t-SNE
  • 原文地址:https://www.cnblogs.com/jackStudy/p/4364391.html
Copyright © 2011-2022 走看看