C++ Primer 学习笔记_60_重载操作符与转换 --赋值、下标、成员访问操作符(一)

2014-11-24 12:34:38 · 作者: · 浏览: 0

重载操作符与转换

--赋值、下标、成员访问操作符



一、赋值操作符

类赋值操作符接受类类型形参,通常该形参是对类类型的const引用,但也可以是类类型或对类类型的非const引用。如果没有定义这个操作符,则编译器将合成它。类赋值操作符必须是类的成员,以便编译器可以知道是否需要合成一个。而且还可以为一个类定义许多附加的赋值操作符,这些赋值操作符会因为右操作数的不同而构成重载!如string类型:

    string car("Volks");
    car = "Studebaker"; //接受C风格字符串实参

    string model;
    model = 'T';        //接受字符实参
    model = car;        //接受string实参


为了支持这些操作符,string类应包含如下的成员:

class string
{
public:
    string &operator=(const string &);
    string &operator=(const char *);
    string &operator=(char);

    //...
};

赋值操作符可以重载,无论形参为何种类型,赋值操作符都必须定义为成员函数!这一点与复合赋值操作符不同。


赋值必须返回*this的引用

为了与内置类型达成一致,赋值返回一个引用,同时也可以不用创建和撤销结果的临时副本。返回值通常是左操作数的引用:

Sales_item &Sales_item::operator+=(const Sales_item &rhs)
{
    units_sold += rhs.units_sold;
    revenue += rhs.revenue;

    return *this;
}

【最佳实践】

一般而言:赋值操作符和复合赋值操作符应返回左操作数的引用!

//P442 习题14.14
Sales_item &Sales_item::operator=(const string &str)
{
    isbn = str;

    return *this;
}


//习题14.15/16
class CheckoutRecord
{
public:
    typedef unsigned Date;
    //...
    CheckoutRecord &operator=(const CheckoutRecord &rhs);
    //新添加一本书
    CheckoutRecord &operator=(const string &);
    //新添加一位等待读者
    CheckoutRecord &operator=(const pair
  
    &);

private:
    double book_id;
    string title;
    Date date_borrowed;
    Date date_due;
    pair
   
     borrower; vector< pair
    
      * > wait_list; }; CheckoutRecord &CheckoutRecord::operator=(const CheckoutRecord &rhs) { book_id = rhs.book_id; title = rhs.title; date_borrowed = rhs.date_borrowed; date_due = rhs.date_due; borrower = rhs.borrower; //为vector赋值 wait_list.clear(); for (vector< pair
     
       * >::const_iterator iter = rhs.wait_list.begin(); iter != rhs.wait_list.end(); ++iter) { pair
      
        *ppair = new pair
       
        ; *ppair = **iter; //复制的是,vector中的对象,而不是指针! wait_list.push_back(ppair); } return *this; } CheckoutRecord &CheckoutRecord::operator=(const string &Title) { title = Title; return *this; } CheckoutRecord &CheckoutRecord::operator=(const pair
        
          &newReader) { pair
         
           *ppair = new pair
          
           ; *ppair = newReader; wait_list.push_back(ppair); return *this; } 
          
         
        
       
      
     
    
   
  

二、下标操作符

可以从容器中检索单个元素的容器类一般会定义下标操作符,即operator[]。如vector和string。

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


1、提供读写访问

定义下标操作符比较复杂的地方在于,它在用作赋值的左右操作符数时都应该能表现正常。下标操作符出现在左边,必须生成左值,可以指定引用作为返回类型而得到左值。只要下标操作符返回引用,就可用作赋值的任意一方。

【最佳实践】

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


2、原型下标操作

class Foo
{
public:
    int &operator[] (const size_t);
    const int &operator[] (const size_t) const;

private:
    vector
  
    data;
};

int &Foo::operator[](const size_t index)
{
    return data[index];	//注意:没有范围检测...
}

//除了函数原型不同之外,没有其他任何差别!
const int &Foo::operator[] (const size_t index) const
{
    return data[index];
}

  

//P443 习题14.17/18/19
class CheckoutRecord
{
public:
    typedef unsigned Date;
    typedef vector< pair
  
    *>::size_type sizeType;
    //...

    pair
   
     &operator[] (const size_t); const pair
    
      &operator[] (const size_t) const; const pair
     
       &get_a_waiter(sizeType) const; private: double book_id; string title; Date date_borrowed; Date date_due; pair
      
        borrower; vector< pair
       
         * > wait_list; }; pair
        
          &CheckoutRecord::operator[](const size_t index) { return *wait_list.at(index); } const pair
         
           &CheckoutRecord::operator[](const size_t index) const { return *wait_list.at(index); } /**虽然下标操作符使用简单,但是他也有他的缺点 *如:下标操作符适合于表示“获取容器中特定元素”的语义 *而获取一个等待者则语义不明 *这样就不如使用一个普通的成员函数表意明确! */ //其实就是将函数原型做了稍微的改动,其他方面都不做更改 const pair
          
            &CheckoutRecord: