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/ ...
随机推荐
- JQuery 插件FlexiGrid 之完全配置与使用
博客分类: Java综合 jQuery配置管理jsonServlet数据结构 自己再做这个的时候.也是找了很多资料..但网上搜索了很多资料. 没有介绍的很全的. 鄙人就在此献丑一下. 来全面的介绍一 ...
- html——SVG
SVG 指可伸缩矢量图形 (Scalable Vector Graphics) SVG 用于定义用于网络的基于矢量的图形 SVG 使用 XML 格式定义图形 SVG 图像在放大或改变尺寸的情况下其图形 ...
- SparkSQL使用之Spark SQL CLI
Spark SQL CLI描述 Spark SQL CLI的引入使得在SparkSQL中通过hive metastore就可以直接对hive进行查询更加方便:当前版本中还不能使用Spark SQL C ...
- SQL Server设置主键自增长列
1.新建一数据表,里面有字段id,将id设为为主键 create table tb(id int,constraint pkid primary key (id)) create table tb(i ...
- VISUAL STUDIO 2008 WINDOWS FORM项目发布生成安装包详解(转)
转自:http://www.cnblogs.com/killerofyang/archive/2012/05/31/2529193.html Visual Studio 2008 Windows Fo ...
- 【Unity Shaders】学习笔记——SurfaceShader(六)混合纹理
[Unity Shaders]学习笔记——SurfaceShader(六)混合纹理 转载请注明出处:http://www.cnblogs.com/-867259206/p/5619810.html 写 ...
- FFTW库在VS 2010中的使用方法
一.FFTW库简介(from百度百科) FFTW ( the Faster Fourier Transform in the West) 是一个快速计算离散傅里叶变换的标准C语言程序集,其 ...
- 是否连接VPN
//需要导入ifadds头文件 //是否连接VPN - (BOOL)isVPNConnected{ struct ifaddrs *interfaces = NULL; struct ...
- hbase查询,scan详解
一.shell 查询 hbase 查询相当简单,提供了get和scan两种方式,也不存在多表联合查询的问题.复杂查询需通过hive创建相应外部表,用sql语句自动生成mapreduce进行.但是这种简 ...
- Windows USN Journal Parsing
What is "USN Journal"? It is "Update Sequence Number Journal". It records change ...