第7章 运算符重载
7.1.1 重载运算符的限制
不能重载的算符
. :: .* ?: sizeof
可以重载的运算符
+ - * / % ^ & | ~
! = < > += -= *= /= %
^= &= |= << >> >>= <<= == !=
<= >= && || ++ -- ->* ‘ ->
[] () new delete new[] delete[]
重载运算符函数可以对运算符作出新的解释,但原有基本语义不变:
Ø 不改变运算符的优先级
Ø 不改变运算符的结合性
Ø 不改变运算符所需要的操作数
Ø 不能创建新的运算符
Ø 运算符函数可以重载为成员函数或友元函数
7.2 用成员或友元函数重载运算符
1.一元运算符
Object op 或 op Object
Ø 重载为成员函数,解释为:
Object. operator op ()
操作数由对象Object通过this指针隐含传递
Ø 重载为友元函数,解释为:
operatorop (Object)
操作数由参数表的参数Object提供
2.二元运算符
ObjectL op ObjectR
Ø 重载为成员函数,解释为:
ObjectL . operator op ( ObjectR )
左操作数由ObjectL通过this指针传递,右操作数由参数ObjectR传递
Ø 重载为友元函数,解释为:
operator op ( ObjectL, ObjectR )
左右操作数都由参数传递
成员运算符函数的原型在类的内部声明格式如下:
class X {
//…
返回类型 operator运算符(形参表);
//…
}
在类外定义成员运算符函数的格式如下:
返回类型 X::operator运算符(形参表)
{
函数体
}
7.2.2 用友元函数重载
class Complex
{ int Real ; int Imag ;
public:
Complex ( int a ) { Real = a ; Imag = 0 ; }
Complex ( int a ,int b ) { Real = a ; Imag = b ; }
Complex operator + ( Complex ) ;
…...
} ;
int f ( )
{Complex z ( 2 , 3 ) , k ( 3 , 4 ) ;
z = z + 27 ;
z = 27 + z ;
…...
}
Ø 在第一个参数需要隐式转换的情形下,使用友元函数重载
运算符是正确的选择
Ø 友元函数没有 this 指针,所需操作数都必须在参数表显式
声明,很容易实现类型的隐式转换
Ø C++中不能用友元函数重载的运算符有
= () [] ->
成员运算符函数与友元运算符函数的比较
(1) 成员运算符函数比友元运算符函数少带一个参数(后置的++、--需要增加一个形参)。
(2) 双目运算符一般可以被重载为友元运算符函数或成员运算符函数,但当操作数类型不相同时,必须使用友元函数。
7.3 几个典型运算符重载
设 A Aobject ;
运算符 ++和 - - 有两种方式:
前置方式: ++Aobject --Aobject
成员函数 重载 A :: A operator++ () ;
解释为: Aobject . operator ++( ) ;
友元函数 重载 friend A operator++ (A &) ;
解释为: operator ++( Aobject ) ;
成员函数 重载 A :: A operator++ (int) ;
解释为: Aobject . operator ++( 0 ) ;
友元函数 重载: friend A operator++ (A &, int) ;
解释为: operator++(Aobject, 0)
7.3.2 重载赋值运算符
Ø 赋值运算符重载用于对象数据的复制
Ø operator= 必须重载为成员函数
Ø 重载函数原型为:
类名 & 类名 :: operator= ( 类名 ) ;
7.3.3 重载运算符[]和()
Ø 运算符[] 和 () 是二元运算符
Ø [] 和 ()只能用成员函数重载,不能用友元函数重载
1.重载下标运算符 []
[] 运算符用于访问数据对象的元素
重载格式 类型 类 ::operator[] ( 类型 ) ;
例
设 x 是类 X 的一个对象,则表达式
x [ y ]
可被解释为
x . operator [ ] ( y )
2.重载函数调用符 ()
() 运算符用于函数调用
重载格式 类型 类 ::operator() ( 参数表 ) ;
例
设 x 是类 X 的一个对象,则表达式
x ( arg1, arg2, … )
可被解释为
x . operator () (arg1, arg2, … )
7.3.4 重载流插入和流提取运算符
Ø istream 和 ostream 是 C++的预定义流类
Ø cin 是 istream 的对象,cout是 ostream 的对象
Ø 运算符<< 由ostream 重载为插入操作,用于输出基本类型数据
Ø 运算符>> 由 istream 重载为提取操作,用于输入基本类型数据
Ø 用友元函数重载<< 和 >> ,输出和输入用户自定义的数据类型
重载输出运算符“<<”(只能被重载成友元函数,不能重载成成员函数)
定义输出运算符“<<”重载函数的一般格式如下:
ostream&operator<<(ostream& out,class_name& obj)
{
out<
out<
.. .
out<
return out;
}
重载输入运算符“>>” (只能被重载成友元函数)
定义输入运算符函数 “>>”重载函数的一般格式如下:
istream&operator>>(istream& in,class_name& obj)
{
in>>obj.item1;
in>>obj.item2;
. . .
in>>obj.itemn;
return in;
}
1.
n 定义point类,重载>>,<<运算符,实现point对象的输入、输出
n 定义复数Complex类,重载>>,<<运算符,实现Complex对象的输入、输出
n #include
n class Point{
n int x,y;
n public:
n friend istream & operator >>(istream & in, Point&p);
n friend ostream & operator<<(ostream & out, Point&p);
n };
n istream & operator>>(istream & in, Point &p){
n cout<<"Please input a point:"<
n in>>p.x; in>>p.y; return in;}
n ostream &operator<<(ostream & out, Point &p){
n out<<"("<
n int main(){
n Point p;
n cin>>p;
n cout<
n return 0;
n }
2.
设计一个集合类,用无符号整数数组表示集合,重载运算符实现集合的基本运算,以及集合元素的输入、输出。
//setTypeHead.h
#include
using namespace std;
//集合类
class setType
{ public:
setType( unsigned e=128 ); //构造函数
setType( const setType & B ); //复制构造函数
~setType(); //析构函数
setType operator+= ( unsigned x ); //重载+=,把元素x并入集合
setType operator= ( setType B ); //重载=,集合变量赋值
setType operator() (unsigned x=0); //重载(),集合置元素x,默认置空
setType operator+ ( setType B ); //重载+,求并集
setType operator* ( setType B ); //重载*,求交集
setType operator- ( setType B ); //重载-,求差集
bool operator<= ( setType B ); //重载<=,判集合蕴含
C++ 标准模板库
C++ Standard Template Libarary
STL概述
n STL是C++标准程序库的核心,深刻影响了标准程序库的整体结构
n STL由一些可适应不同需求的集合类(collectionclass),以及在这些数据集合上操作的算法(algorithm)构成
n STL内的所有组件都由模板(template)构成,其元素可以是任意类型
n STL是所有C++编译器和所有操作系统平台都支持的一种库
n STL组件
n 容阿器(Container)- 管理某类对象的集合
n 迭代器(Iterator) -在对象集合上进行遍历
n 算法(Algorithm) -处理集合内的元素
n 容器适配器(containeradaptor)
n 函数对象(functor)
STL容器的共同能力
所有容器中存放的都是值而非引用。如果希望存放的不是副本,容器元素只能是指针。
所有元素都形成一个次序(order),可以按相同的次序一次或多次遍历每个元素
n STL容器元素的条件
必须能够通过拷贝构造函数进行复制
必须可以通过赋值运算符完成赋值操作
必须可以通过析构函数完称销毁动作
序列式容器元素的默认构造函数必须可用
某些动作必须定义operator ==,例如搜寻操作
关联式容器必须定义出排序准则,默认情况是重载operator <
n STL容器的共同操作
Ø 与大小相关的操作(sizeoperator)
F size()-返回当前容器的元素数量
F empty()-判断容器是否为空
F max_size()-返回容器能容纳的最大元素数量
Ø 比较(comparison)
F ==,!=,<,<=,>,>=
F 比较操作两端的容器必须属于同一类型
F 如果两个容器内的所有元素按序相等,那么这两个容器相等
F 采用字典式顺序判断某个容器是否小于另一个容器
Ø 赋值(assignment)和交换(swap)
F swap用于提高赋值操作效率
Ø 与迭代器(iterator)相关的操作
F begin()-返回一个迭代器,指向第一个元素
F end()-返回一个迭代器,指向最后一个元素之后
F rbegin()-返回一个逆向迭代器,指向逆向遍历的第一个元素
F rend()-返回一个逆向迭代器,指向逆向遍历的最后一个元素之后
n 迭代器(iterator)
Ø 迭代器分类
F 双向迭代器
可以双向行进,以递增运算前进或以递减运算后退、可以用==和!=比较。
list、set和map提供双向迭代器
F 随机存取迭代器
除了具备双向迭代器的所有属性,还具备随机访问能力。
可以对迭代器增加或减少一个偏移量、处理迭代器之间的距离或者使用<和>之类的关系运算符比较两个迭代器。
vector、deque和string提供随机存取迭代器
n vector
Ø vector模拟动态数组
Ø vector的元素可以是任意类型T,但必须具备赋值和拷贝能力(具有public拷贝构造函数和重载的赋值操作符)
Ø 必须包含的头文件#include
Ø vector支持随机存取
Ø vector的大小(size)和容量(capacity)
F size返回实际元素个数,
F capacity返回vector能容纳的元素最大数量。如果插入元素时,元素个数超过capacity,需要重新配置内部存储器。
操作 |
效果 |
vector |
产生空的vector |
vector |
产生同类型的c1,并将复制c2的所有元素 |
vector |
利用类型T的默认构造函数和拷贝构造函数生成一个大小为n的vector |
vector |
产生一个大小为n的vector,每个元素都是e |
vector |
产生一个vector,以区间[beg,end]为元素初值 |
~vector |
销毁所有元素并释放内存。 |
操作 |
效果 |
c.size() |
返回元素个数 |
c.empty() |
判断容器是否为空 |
c.max_size() |
返回元素最大可能数量(固定值) |
c.capacity() |
返回重新分配空间前可容纳的最大元素数量 |
c.reserve(n) |
扩大容量为n |
c1==c2 |
判断c1是否等于c2 |
c1!=c2 |
判断c1是否不等于c2 |
c1 |
判断c1是否小于c2 |
c1>c2 |
判断c1是否大于c2 |
c1<=c2 |
判断c1是否大于等于c2 |
c1>=c2 |
判断c1是否小于等于c2 |
n map/multimap
Ø 构造、拷贝和析构
操作 |
效果 |
map c |
产生空的map |
map c1(c2) |
产生同类型的c1,并复制c2的所有元素 |
map c(op) |
以op为排序准则产生一个空的map |
map c(beg,end) |
以区间[beg,end]内的元素产生一个map |
map c(beg,end,op) |
以op为排序准则,以区间[beg,end]内的元素产生一个map |
~ map() |
销毁所有元素并释放内存。 |
Ø 非变动性操作
操作 |
效果 |
c.size() |
返回元素个数 |
c.empty() |
判断容器是否为空 |
c.max_size() |
返回元素最大可能数量 |
c1==c2 |
判断c1是否等于c2 |
c1!=c2 |
判断c1是否不等于c2 |
c1 |
判断c1是否小于c2 |
c1>c2 |
判断c1是否大于c2 |
c1<=c2 |
判断c1是否大于等于c2 |
c1>=c2 |
判断c1是否小于等于c2 |
Ø 赋值
操作 |
效果 |
c1 = c2 |
将c2的全部元素赋值给c1 |
c1.swap(c2) |
将c1和c2的元素互换 |
swap(c1,c2) |
同上,全局函数 |
Ø 特殊搜寻操作
操作 |
效果 |
count(key) |
返回”键值等于key”的元素个数 |
find(key) |
返回”键值等于key”的第一个元素,找不到返回end |
lower_bound(key) |
返回”键值大于等于key”的第一个元素 |
upper_bound(key) |
返回”键值大于key”的第一个元素 |
equal_range(key) |
返回”键值等于key”的元素区间 |
n map/multimap
Ø 安插(insert)元素
操作 |
效果 |
c.erase(pos) |
删除迭代器pos所指位置的元素,无返回值 |
c.erase(val) |
移除所有值为val的元素,返回移除元素个数 |
c.erase(beg,end) |
删除区间[beg,end]内所有元素,无返回值 |
c.clear() |
移除所有元素,清空容器 |
STL容器
操作 |
效果 |
begin() |
返回指向第一个元素的迭代器 |
clear() |
清除所有元素 |
count() |
返回某个值元素的个数 |
empty() |
如果集合为空,返回true |
end() |
返回指向最后一个元素的迭代器 |
equal_range() |
返回集合中与给定值相等的上下限的两个迭代器 |
erase() |
删除集合中的元素 |
find() |
返回一个指向被查找到元素的迭代器 |
get_allocator() |
返回集合的分配器 |
pair模板:
pair模板可以用于生成key-value对
#include
#include
using namespace std;
main() {
typedefset<double,less
constint SIZE = 5;
doublea[SIZE] = {2.1,4.2,9.5,2.1,3.7 };
double_setdoubleSet(a,a+SIZE);
ostream_iterator
cout<< "1) ";
copy(doubleSet.begin(),doubleSet.end(),output);
cout<< endl;
pair<double_set::const_iterator, bool> p;
p= doubleSet.insert(9.5);
if(p.second)
cout<< "2) " << * (p.first) << " inserted" << endl;
else
cout<< "2) " << * (p.first) << " not inserted" << endl;
}
//insert函数返回值是一个pair对象, 其first是被插入
输出:
1)2.1 3.7 4.2 9.5
2)9.5 not inserted
重载运算符在我看来主要是用来使对象之间可以做运算操作的.
对于STL的应用,虽然是个方便的方法,不过一直处于似懂非懂的状态,不知道该如何用它代替平时学的方式,自我感觉很有难度。。。