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

来源:互联网 发布:为什么开不了淘宝店铺 编辑:程序博客网 时间:2024/05/01 18:58

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_dataoperator + (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 bookSales_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 objectStrBlobPtr& 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 valueStrBlobPtr 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 thedecrement    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 operatorint 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.既没有转换又没有重载+,该表达式非法。

0 0
原创粉丝点击