14.1 重载操作符的定义

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

不能为任何内置类型定义额外的新的操作符;优先级和结合性是固定的;不再具备短路求值特性(不建议重载&&、||、逗号);

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

使用重载操作符的方式:

1)  与内置类型使用操作符方式一样;

2)  也可像调用普通函数一样调用重载操作符函数,指定函数并传递适当类型适当数目的形参;

item1 += item2; // expression based "call"
item1.operator+=(item2); // equivalent call to member operator function

重载操作符的设计

1)不要重载具有内置含义的操作符。如果没有特定重载版本,编译器就自己定义以下这些操作符:

- 合成赋值操作符(=):逐个成员赋值

- 取地址操作符(&)、逗号操作符(,)与内置含义一致

- 内置逻辑与(&&)和逻辑或(||)操作符使用短路求值,重新定义将会失去该特征。

2)大多数操作符对类对象没有意义,设计类的时候应该确定要支持哪些操作符。

3)复合赋值操作符。如果一个类有算术操作符或位操作符,那么提供相应的复合赋值操作符一般是个好的做法。

4)相等和关系操作符。将用作关联容器类型的类应定义<操作符;即使类只存储在顺序容器中,也应该定义相等操作符和小于操作符;如果类定义了相等操作符,它也应该定义不等操作符。

5)选择成员或非成员实现(经验原则)

- 赋值下标调用和成员访问箭头(=、[ ]、( )、->)等操作符必须定义为成员,将这些操作符定义为非成员将在编译时标记为错误;

- 复合赋值通常定义为类的成员(不是必须这样做);

- 改变对象状态或与给定类型紧密联系的一些操作符通常定义为成员,如自增自减解引用

- 对称操作符,如算术、相等、关系和位操作符,最好定义为非成员。

14.2 输入和输出操作符

输出操作符<<的重载

ostream&
operator<<(ostream& out, const Sales_item& s)
{out << s.isbn << "\t" << s.units_sold << "\t"<< s.revenue << "\t" << s.avg_price();return out;
}//注意:IO操作符必须为非成员函数

输入操作符>>的重载

istream&
operator>>(istream& in, Sales_item& s)
{double price;in >> s.isbn >> s.units_sold >> price;// check that the inputs succeededif (in)s.revenue = s.units_sold * price;elses = Sales_item(); // input failed: reset object to default statereturn in;
}

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

一般而言,将算术和关系操作符定义为非成员函数

算术操作符

// assumes that both objects refer to the same isbn
Sales_item
operator+(const Sales_item& lhs, const Sales_item& rhs)
{Sales_item ret(lhs); // copy lhs into a local object that we'll returnret += rhs; // add in the contents of rhsreturn ret; // return ret by value
} 

注意:同时定义了算术操作符和相关复合赋值操作符的类,一般用复合赋值实现算术操作

相等操作符

inline bool
operator==(const Sales_item &lhs, const Sales_item &rhs)
{// must be made a friend of Sales_itemreturn 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 in terms of operator==
}

14.4 赋值操作符

赋值操作符必须是类的成员,赋值必须返回对*this的引用

14.5 下标操作符

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

class Foo {
public:int &operator[] (const size_t);const int &operator[] (const size_t) const;// other interface members
private:vector<int> data;// other member data and private utility functions
}; 

14.6 成员访问操作符

箭头(->)操作符一般为类成员,解引用(*)不要求定义为成员,但将它作为成员也是正确的。

class ScreenPtr {
public:// constructor and copy control members as beforeScreen &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; // points to use-counted ScrPtr class
}; 

重载解引用

分别定义解引用操作的const和非const版本;const成员返回const引用以防止用户改变基础对象。

重载箭头操作符

表现得像二元操作符:接受一个对象和一个成员名。对对象解引用以获取成员,—>的右操作数对应着类成员的一个标识符。

当编写:point->action();

由于优先级规则,等价于 (point->action)();

1)如果point是指针,指向具有action成员的类对象,编译器将代码编译为调用该对象的action成员;

2)如果point是定义了operator->操作符的类,则point->action与point.operator->()->action相同,然后使用该结果重复这三步。

3)否则,代码出错。

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

14.7 自增操作符和自减操作符

C++不要求自增自减一定作为类的成员,但是因为这些操作符改变对象状态,故倾向于作为成员。

/*
* smart pointer: Checks access to elements throws an out_of_range
* exception if attempt to access a nonexistent element
* users allocate and free the array
*/
class CheckedPtr {
public:// no default constructor; CheckedPtrs must be bound to an objectCheckedPtr(int *b, int *e): beg(b), end(e), curr(b) { }// dereference and increment operations
private:int* beg; // pointer to beginning of the arrayint* end; // one past the end of the arrayint* curr; // current position within the array
};

前自增/自减(返回对象的引用)

class CheckedPtr {
public:CheckedPtr& operator++(); // prefix operatorsCheckedPtr& operator--();// other members as before
};// prefix: return reference to incremented/decremented object
CheckedPtr& CheckedPtr::operator++()
{if (curr == end)throw out_of_range("increment past the end of CheckedPtr");++curr; // advance current statereturn *this;
}CheckedPtr& CheckedPtr::operator--()
{if (curr == beg)throw out_of_range("decrement past the beginning of CheckedPtr");--curr; // move current state back one elementreturn *this;
} 

后自增/自减(返回对象的旧值)

为做区别,后缀操作符接受一个额外的int形参,使用时编译器提供0初始化它

class CheckedPtr {
public:// increment and decrementCheckedPtr operator++(int); // postfix operatorsCheckedPtr operator--(int);// other members as before
};// postfix: increment/decrement object but return unchanged value
CheckedPtr CheckedPtr::operator++(int)
{// no check needed here, the call to prefix increment will do the checkCheckedPtr ret(*this); // save current value++*this; // advance one element, checking the incrementreturn ret; // return saved state
}
CheckedPtr CheckedPtr::operator--(int)
{// no check needed here, the call to prefix decrement will do the checkCheckedPtr ret(*this); // save current value--*this; // move backward one element and checkreturn ret; // return saved state
}

调用

CheckedPtr parr(ia, ia + size); // iapoints to an array of ints
parr.operator++(0); // call postfix operator++
parr.operator++(); // call prefix operator++

14.8 调用操作符和函数对象

函数调用操作符必须声明为成员函数。定义了调用操作符的类,其对象常称为函数对象(function object),即它们是行为类似函数的对象。

struct absInt {int operator() (int val) {return val < 0 ? -val : val;}
};int i = -42;
absInt absObj; // object that defines function call operator
unsigned int ui = absObj(i); // calls absInt::operator(int)

将函数对象用于标准库算法

谓词(predicate)是做某些检测的函数,返回用于条件判断的类型,指出条件是否成立。

// determine whether a length of a given word is 6 or more
bool GT6(const string &s)
{return s.size() >= 6;
}vector<string>::size_type wc =
count_if(words.begin(), words.end(), GT6);

函数对象可以更灵活

// determine whether a length of a given word is longer than a stored bound
class GT_cls {
public:GT_cls(size_t val = 0): bound(val) { }bool operator()(const string &s){ return s.size() >= bound; }
private:std::string::size_type bound;
};
cout << count_if(words.begin(), word.end(), GT_cls(6)<< " words 6 characters or longer" << endl;

标准库定义的函数对象

标准库定义了一组算术、关系与逻辑函数对象类,以及一组函数适配器,用于特化或扩展标准库所定义的以及自定义的函数对象类。标准库函数对象类型在functional头文件定义。

不同的函数对象定义了执行不同操作符的调用操作符;两个一元函数对象类:negate<Type>(一元减),logical_not<Type>(逻辑非)

每个函数对象类都是一个模板,我们需要为该模板提供一个类型

plus<int> intAdd; // function object that can add two int values
negate<int> intNegate; // function object that can negate an int value
// uses intAdd::operator(int, int) to add 10 and 20
int sum = intAdd(10, 20); // sum = 30
// uses intNegate::operator(int) to generate -10 as second parameter
// to intAdd::operator(int, int)
sum = intAdd(10, intNegate(10)); // sum = 0

函数对象常用于覆盖算法使用的默认操作符。

// passes temporary function object that applies > operator to two strings
sort(svec.begin(), svec.end(), greater<string>());

函数对象的函数适配器

1)绑定器(bind1st,bind2nd)

count_if(vec.begin(), vec.end(), bind2nd(less_equal<int>(), 10));

2)求反器(not1,not2)

count_if(vec.begin(), vec.end(), not1(bind2nd(less_equal<int>(), 10)));

14.9 转换与类类型

一个实参调用的非explicit构造函数定义了一个隐式转换,这种构造函数定义了到类型的转换。我们还可以定义从类型的转换,像其他转换一样,编译器将自动应用这个转换。

转换操作符

转换操作符是一种特殊的类成员函数。它定义将类类型转变为其他类型值的转换。转换操作符在类定义体内声明,在operator后跟着转换的目标类型。通用形式:

operator type();

1)不允许转换为数组或函数类型,转换为指针和引用是可以的;

2)转换函数必须是成员函数,不能指定返回类型,但是必须显式返回一个指定类型的值,形参表空;

3)因不改变被转换的对象,通常定义为const成员

转载于:https://www.cnblogs.com/itree/p/4908132.html

[c++primer][14]重载操作符与转换相关推荐

  1. C++复习 14 重载操作符与转换

    声明,所有的朋友,如果要转我的帖子,务必注明"作者:黑啤来源:CSDN博客"和 具体的网络地址http://blog.csdn.net/nx500/archive/2007/10/ ...

  2. 读书笔记(C++)————【重载操作符与转换】

    //14.重载操作符与转换//14.1 重载操作符的定义//不能重载的操作符:: .* . ?://重载操作符必须具有至少一个类类型或枚举类型的操作数//优先级和结合性是固定的//不再具备短路求值特性 ...

  3. C++ Primer 学习笔记_62_重载操作符与转换 --调用操作符和函数对象

    重载操作符与转换 --调用操作符和函数对象 引言: 能够为类类型的对象重载函数调用操作符:一般为表示操作的类重载调用操作符! struct absInt {int operator() (int va ...

  4. C++ 重载操作符与转换

    <C++ Primer 4th>读书笔记 重载操作符是具有特殊名称的函数:保留字 operator 后接需定义的操作符号. Sales_item operator+(const Sales ...

  5. 第十四章 重载操作符与转换

    code: /*第14章 重载操作符与转换14.1 重载操作符的定义 14.2 输入和输出操作符 14.3 算术操作符和关系操作符 14.4 赋值操作符 14.5 下标操作符 14.6 成员访问操作符 ...

  6. c++ primer读书笔记-第十四章 重载操作符与转换

    C++ 允许我们重定义操作符用于类类型对象时的含义.如果需要,可以像内置转换那样使用类类型转换,将一个类型的对象隐式转换到另一类型. 例如标准库为容器类定义了几个重载操作符.这些容器类定义了下标操作符 ...

  7. 《C++ Primer》之重载操作符与转换(中)

    赋值操作符 类赋值操作符接受类类型形参,通常,该形参是对类类型的 const 引用,但也可以是类类型或对类类型的非 const 引用.如果没有定义这个操作符,则编译器将合成它.类赋值操作符必须是类的成 ...

  8. 重载操作符与转换(上)

    重载操作符的作用: 通过操作符重载,程序员能够针对类类型的操作数定义不同的操作符版本.程序用移位操作符(>> 和 <<)进行输入输出,用加号操作符(+)将两个 Sales_it ...

  9. 重温C++ primer 之重载符操作与转换总结

    重载操作符必须至少一个类类型或枚举类型的操作数.这条规则强制重载操作符不能重新定义用于内置类型对象的操作的含义. 重载操作符时不能使用默认实参. 重载操作符的设计 1.不要重载具有内置含义的操作符 重 ...

最新文章

  1. 把命令行玩成“迷你谷歌”:可搜索、计算,还能翻译 | GitHub热榜
  2. 转载--httpclient原理和应用
  3. 细述vim编码格式配置
  4. Linux 用户进程内存空间详解
  5. php validator,实用的PHP验证器类Validator
  6. 从搭建脚手架到在npm上发布react组件
  7. 【控制】《多智能体系统一致性与复杂网络同步控制》郭凌老师-第4章-具有扰动的混沌系统主-从同步
  8. java对cookie的操作_java对cookie的操作
  9. 在RHEL6.6环境下进行LVS-NAT实验(Vmware模式)
  10. face recongnition
  11. node --- 在express中配置使用模板引擎(art-template)
  12. 南岸焊接机器人厂_造船三部高效焊接工艺技术年鉴
  13. 关闭vue中的eslint校验
  14. box怎么用 latency_box-sizing使用场景
  15. 替代传统C/S和B/S技术的下一代客户/服务器编程技术
  16. java学习软件_刚学习java,用哪些学习软件比较好?
  17. Eureka服务治理
  18. (2020年下半年软件设计师49题)程序设计语言的大多数语法现象可以用CFG(上下文无关文法)表示。下面的CFG产生式集用于描述简单算术表达式,其中+ - * 表示加、减、乘运算,id表示单个字母表示
  19. undefined reference to 的报错原因记录
  20. python剔除数据_python实现对excel进行数据剔除操作实例

热门文章

  1. 日本小学生毕业典礼被全世界围观:疫情之下在《我的世界》中补办一场!
  2. 2021美赛B题论文第一篇
  3. 冯诺依曼计算机的运行原理
  4. 【强化学习论文合集】二十六.2020国际人工智能联合会议论文(IJCAI2020)
  5. OpenFOAM——孔板流量计
  6. 鸿蒙系统手机一览表,华为鸿蒙os系统支持的手机型号有哪些?鸿蒙os适配机型列表一览[多图]...
  7. 大概这就是“无监督学习”的机器学习算法实例
  8. sqlserver当前属于哪个季度_sqlserver日期推算(年,季度,月,星期推算)
  9. R语言结构方程模型SEM、路径分析房价和犯罪率数据、预测智力影响因素可视化2案例
  10. java bll dal_DAL层与BLL层的设计原则