重学C++ (九) 重载操作符与转换

1.重载操作符必须具有至少一个类类型或枚举类型的操作数(内置类型的操作符含义不能改变);

2.除了函数调用操作符operator()之外,重载操作符时不能使用默认实参;

3.重载之后&&, ||不再具备短路求值特征;

4.作为成员函数的操作符有一个隐含的this形参,限定为第一个操作数;
一般将算数和关系操作符定义为非成员函数,而将赋值操作符定义为成员:

//成员函数
Sales_item& Sales_item::operator += (const Sales_item&);
//非成员函数
Sales_item operator + (const Sales_item&, const Sales_item&);

5.操作符定义为非成员函数时,通常需要将它们设置为所操作类的友元(这样才能访问私有数据成员);

6.赋值(=)、下标([ ])、调用(( ))、和成员访问箭头(->)必须定义为成员函数;
IO操作符必须为非成员函数,类通常将IO操作符设为友元;

7.输入输出操作符重载(必须为非成员函数)

//输出操作符,返回流的引用。
//输出不修改值,所以第二个参数为const引用
ostream& operator << (ostream & out, const ClassType & obj)
{
    //doSomething
    out<< // ...
    return out;
}

//输入操作符,返回流的引用。
//输入修改值,所以第二个参数为非const引用
istream& operator >> (istream & in, ClassType & obj)
{
    //doSomething
    in>> // ...
    //注意需要处理输入错误以及文件结束等情况!
    return in;
}

//例子:
istream& operator >> (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(); //输入失败,reset to default state
    return in;
}

8.算术操作符和关系操作符

// assumes that both objects refer to the same book
//加法返回的是一个右值,而不是引用
Sales_data
operator + (const Sales_data &lhs, const Sales_data &rhs)
{
    Sales_data sum = lhs;  // copy data members from lhs into sum
    sum += rhs;             // add rhs into sum,前提是定义了+=操作符
    return sum;
}


bool 
operator == (const Sales_data &lhs, const Sales_data &rhs)
{
    return lhs.isbn() == rhs.isbn() &&
           lhs.units_sold == rhs.units_sold &&
           lhs.revenue == rhs.revenue;
}

bool 
operator != (const Sales_data &lhs, const Sales_data &rhs)
{
    return !(lhs == rhs); //通过 == 操作符来定义!=
}

9.赋值操作符

// = 操作符
StrVec& 
StrVec::operator=(initializer_list<string> il)
{
    // alloc_n_copy allocates space and copies elements from the given range
    auto data = alloc_n_copy(il.begin(), il.end());
    free();   // destroy the elements in this object and free the space
    elements = data.first; // update data members to point to the new space
    first_free = cap = data.second;
    return *this;
}

// += 操作符
// member binary operator: left-hand operand is bound to the implicit this pointer
// assumes that both objects refer to the same book
Sales_data& 
Sales_data::operator+=(const Sales_data &rhs)
{
    units_sold += rhs.units_sold;
    revenue += rhs.revenue;
    return *this;
}

10.下标操作符*

//类定义下标操作符时,一般需要定义两个版本:
//非const成员并返回引用;
//const成员并返回const引用;
class StrVec {
public:
    std::string& operator [] (std::size_t n)
        { return elements[n]; }
    const std::string& operator [] (std::size_t n) const
        { return elements[n]; }
private:
    std::string *elements;   // pointer to the first element in the array
};

11.自增、自减操作符

//前缀自增自减,返回自身的引用
class StrBlobPtr {
public:
    // increment and decrement
    StrBlobPtr& operator++();       // prefix operators
    StrBlobPtr& operator--();
    // other members as before
};

// prefix: return a reference to the incremented/decremented object
StrBlobPtr& 
StrBlobPtr::operator++()
{
    // if curr already points past the end of the container, can't increment it
    check(curr, "increment past end of StrBlobPtr");
    ++curr;       // advance the current state
    return *this;
}

StrBlobPtr& 
StrBlobPtr::operator--()
{
    // if curr is zero, decrementing it will yield an invalid subscript
    --curr;       // move the current state back one element
    check(-1, "decrement past begin of StrBlobPtr");
    return *this;
}


//后缀自增自减,先保存原值,自增后返回自增前的值,故不用引用;
//为区别前缀和后缀,后缀操作符函数接收一个无用的int型形参;
//在后缀操作符中,可以使用前缀操作符来实现自增自减;
class StrBlobPtr {
public:
    // increment and decrement
    StrBlobPtr operator++(int);    // postfix operators
    StrBlobPtr operator--(int);
    // other members as before
};

// postfix: increment/decrement the object but return the unchanged value
StrBlobPtr 
StrBlobPtr::operator++(int)
{
    // no check needed here; the call to prefix increment will do the check
    StrBlobPtr ret = *this;   // save the current value
    ++*this;     // advance one element; prefix ++ checks the increment
    return ret;  // return the saved state
}

StrBlobPtr 
StrBlobPtr::operator--(int)
{
    // no check needed here; the call to prefix decrement will do the check
    StrBlobPtr ret = *this;  // save the current value
    --*this;     // move backward one element; prefix -- checks the
decrement
    return ret;  // return the saved state
}

12.调用操作符和函数对象

struct absInt {
    int operator()(int val) const {
        return val < 0 ? -val : val;
    }
};

//定义了调用操作符的类,其对象称为函数对象;
int i = -42;
absInt absObj;      // object that has a function-call operator
int ui = absObj(i); // passes i to absObj.operator()

**标准库定义了一些函数对象,在functional头文件中定义;

13.转换与类类型

class SmallInt {
public:
    SmallInt(int i = 0): val(i)
    {
        if (i < 0 || i > 255)
            throw std::out_of_range("Bad SmallInt value");
    }
    //转换操作符,必须是成员函数,不能指定返回类型,形参表必须为空
    //一般不应改变被转换的对象,所以为const;
    operator int() const { return val; }
private:
    std::size_t val;
};

//使用
Smallint si;
double dval;
if (si >= dval) //si转换为int,之后再转换为double
    //...
cout << si <<endl; //si转换为int之后调用<<操作符

注意,只允许一次类类型转换:

比如可以Integral->SmallInt->int;但不能Integral->int;

14.给定以下代码:

ClassX sc; int iobj = sc + 3;

有四种可能:

1.有一个重载加操作符与ClassX和int相匹配;

2.存在转换,则先进行类型转换,再进行加操作;

3.既定义了转换操作符又定义了+的重载版本,该表达式具有二义性;

4.既没有转换又没有重载+,该表达式非法。

你可能感兴趣的:(C++,类型转换,重载,操作符)