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<<"\t"<<s.units_sold<<"\t"
<<s.revenue<<"\t"<<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);
}
注解:函数调用操作符必须声明为成员函数。一个类可以定义函数调用操作符的多个版本。有形参的数目或类型加以区别。
C++primer 阅读点滴记录(三)的更多相关文章
- C++primer 阅读点滴记录(一)
第十三章 复制控制:(copy control) 复制构造函数(copy constructor) 复制操作符(assignment operator) ps: 什么时候需要显示的定义复制控制操作:类 ...
- C++primer 阅读点滴记录(二)
智能指针(smart point) 除了增加功能外,其行为像普通指针一样. 一般通过使用计数(use count)或引用计数(reference count)实现智能指针,防止出现指针 ...
- C++PRIMER 阅读笔记 第三章
本章主要介绍 string vector 和 bitset, 不能贪多,现在本文主要介绍 string 与 vector 头文件中最好不要使用namespace std, 因为头文件会直接被预处理器放 ...
- 《大象Think in UML》阅读笔记(三)
Think in UML 阅读笔记(三) 把从现实世界中记录下来的原始需求信息,再换成一种可以知道开发的表达方式.UML通过被称为之概念化的过程来建立适合计算机理解和实现的模型,这个模型被称为分析模型 ...
- Hadoop阅读笔记(三)——深入MapReduce排序和单表连接
继上篇了解了使用MapReduce计算平均数以及去重后,我们再来一探MapReduce在排序以及单表关联上的处理方法.在MapReduce系列的第一篇就有说过,MapReduce不仅是一种分布式的计算 ...
- {django模型层(二)多表操作}一 创建模型 二 添加表记录 三 基于对象的跨表查询 四 基于双下划线的跨表查询 五 聚合查询、分组查询、F查询和Q查询
Django基础五之django模型层(二)多表操作 本节目录 一 创建模型 二 添加表记录 三 基于对象的跨表查询 四 基于双下划线的跨表查询 五 聚合查询.分组查询.F查询和Q查询 六 xxx 七 ...
- JavaScript学习记录三
title: JavaScript学习记录三 toc: true date: 2018-09-14 23:51:22 --<JavaScript高级程序设计(第2版)>学习笔记 要多查阅M ...
- grpc使用记录(三)简单异步服务实例
目录 grpc使用记录(三)简单异步服务实例 1.编写proto文件,定义服务 2.编译proto文件,生成代码 3.编写服务端代码 async_service.cpp async_service2. ...
- 3.VUE前端框架学习记录三:Vue组件化编码1
VUE前端框架学习记录三:Vue组件化编码1文字信息没办法描述清楚,主要看编码Demo里面,有附带完整的代码下载地址,有需要的同学到脑图里面自取.脑图地址http://naotu.baidu.com/ ...
随机推荐
- Ubuntu12.04配置静态ip地址
Ubuntu12.04配置静态ip地址 $sudo gedit /etc/network/interfaces 原有内容只有如下两行: auto lo iface lo inet loopback 向 ...
- V$SGA_RESIZE_OPS.STATUS = ERROR, and MMAN / auto-tuning stops.
Oracle Server - Standard Edition - Version: 10.2.0.3This problem can occur on any platform. SYMPTOMS ...
- zsh配置文件
zsh通过编辑~/.zshrc来配置环境变量,bash通过编辑~/.bash_profile来做同样的事
- 《你不知道的JavaScript》一
1.编译原理 尽管通常将 JavaScript 归类为"动态"或"解释执行"语言,但事实上它是一门编译语言. 在传统编译语言的流程中,程序中的一段源代码在执行之 ...
- [转]windows下设置socket的connect超时
原文地址:http://www.cnblogs.com/BloodAndBone/archive/2012/05/22/2513338.html 变相的实现connect的超时,我要讲的就是这个方法, ...
- unity3d学习重点记录
本文主要是记录在学习unity3d中遇到的重点功能的实现,以及一些API的使用方法.以便在以后使用到的时候查找. 1,给一个UIButton添加执行的事件 // Use this for initia ...
- spark1.4的本地模式编程练习(1)
spark编程练习 申明:以下代码仅作学习参考使用,勿使用在商业用途. Wordcount UserMining TweetMining HashtagMining InvertedIndex Tes ...
- 洛谷P1613 跑路
P1613 跑路 176通过 539提交 题目提供者该用户不存在 标签倍增动态规划 难度普及+/提高 提交该题 讨论 题解 记录 最新讨论 这个题的数据.. 题意问题 表意 题目描述 小A的工作不仅繁 ...
- 使用Cookie保存商品浏览记录
数据流程:页面上是商品列表,点击<a href="productServlet">商品名</a> ==>跳转到自定义的servlet中进行处理,先得到 ...
- [Nginx 1] Nginx简介
导读:现在项目中用到这个Nginx了,本来是想着把代码调通了就得了.想想还是花点时间总结总结,就利用门卫思维吧.今天主要是一个整体的介绍,然后在学习的过程中,接着总结Nginx的其他使用事宜. 一.什 ...