运算符重载
要点:
什么是运算符重载,其意义何在?
以成员函数的形式进行重载
通过友元函数实现重载
++/--/<</>>/=重载
1. 明确目标:为什么要进行运算符重载?
Int x,y;
Y=x+y;
表示两个整数相加,很简洁。但是,两个字符串合并:
Char x[20],y[20];
Strcat(x,y);
表达起来就不如y=x+y;那样直观简洁。
因此,为了表达上的方便,我们进行运算符重载。赋予运算符新的含义,在面对不同类型的对象使用不同的含义。例如:在string类对象x,y的环境下,运算符:“+”,能被解释为字符串x,y的合并。
2.以成员函数实现运算符重载
跟成员函数一个套路,首先在类定义中声明这个运算符,具体形式:
返回类型operator运算符(参数列表);
注:可以在类内定义,也可以在类外定义,在类外定义要使用作用域限定符“::”,
类外定义基本格式:
返回类型 类名::operator运算符(参数列表)
{
}
3.以友元函数的形式重载运算符
运算符重载函数除了可以作为类的成员函数,还可以作为非成员函数。为了不仅能访问类中的公有成员,还能访问私有成员和保护成员,通常运算符重载为友元函数。
运算符重载为友元函数声明格式:
Friend 函数返回类型 operator 运算符(形参表);
4.运算符重载的规则和限制
(1)只能对已有的C++运算符进行重载,而不能臆造新的运算符。
(2)不是所有的运算符都能重载,以下运算符不能重载:
.成员访问运算符
.*成员指针访问运算符
::域运算符
?:条件运算符
Sizeof长度运算符
(3)重载以后四不变:操作数的个数不变,运算符的优先级不变,运算符的结合型不变,运算符的语法结构不变,不能创建新的运算符。
(4)运算符重载函数不能有默认的参数
(5)只能以成员函数形重载的运算符:
[ ]下标运算符
=赋值运算符
()函数调用运算符
->用指针访问对象成员
(6)只能重载为非成员函数的运算符:
流插入运算符<<流提取运算符>>
5. 成员运算符函数与友元运算符函数的比较
(1) 成员运算符函数比友元运算符函数少带一个参数(后置的++、--需要增加一个形参)。
(2) 双目运算符一般可以被重载为友元运算符函数或成员运算符函数,但当操作数类型不相同时,必须使用友元函数。
6.<</>>流插入\输出运算符重载
重载输出运算符“<<”(只能被重载成友元函数,不能重载成成员函数)
定义输出运算符“<<”重载函数的一般格式如下:
ostream& operator<<(ostream& out,class_name&obj)
{
out<<obj.item1;
out<<obj.item2;
.. .
out<<obj.itemn;
return out;
}
重载输入运算符“>>” (只能被重载成友元函数)
定义输入运算符函数“>>”重载函数的一般格式如下:
istream& operator>>(istream& in,class_name&obj)
{
in>>obj.item1;
in>>obj.item2;
. . .
in>>obj.itemn;
return in;
}
7.++/--重载
设 A Aobject ;
运算符 ++和 - - 有两种方式:
前置方式: ++Aobject --Aobject
成员函数 重载 A :: A operator++ () ;
解释为: Aobject . operator ++( ) ;
友元函数 重载 friend A operator++ (A &) ;
解释为: operator ++( Aobject ) ;
后置方式: Aobject ++ Aobject --
成员函数 重载 A :: A operator++ (int) ;
解释为: Aobject . operator ++(0 ) ;
友元函数 重载: friend A operator++ (A &, int) ;
解释为: operator++(Aobject, 0);
成员函数重载:
- #include<bits/stdc++.h>
- using namespace std;
- class Increase
- {
- private:
- int t;
- public:
- Increase(int x):t(x){}
- Increase():t(0){}
- Increase operator ++()//前加运算模板;
- {
- t++;
- return *this;
- }
- Increase operator ++(int x)//后加运算模板
- {
- Increase i(*this);
- t++;
- return i;
- }
- friend ostream & operator<<(ostream &out,Increase & obj)
- {
- out<<obj.t;
- return out;
- }
- };
- int main()
- {
- Increase i,ii,iii,iiii;
- ii=++i;
- cout<<ii<<endl;//i运行结果i=1;
- iiii=iii++;
- cout<<iiii<<endl;//运行结果iiii=0;
- }
友元重载:
- #include<bits/stdc++.h>
- using namespace std;
- class Increase
- {
- private:
- int t;
- public:
- Increase(int x):t(x){}
- Increase():t(0){}
- friend Increase operator ++(Increase & obj)//前加运算模板,多一个对象形参;
- {
- obj.t++;
- return obj;
- }
- friend Increase operator ++(Increase & obj,int )//后加运算模板,可以只有一个int,即不要非得int x;
- {
- Increase i(obj);
- obj.t++;
- return i;
- }
- friend ostream & operator<<(ostream &out,Increase & obj)
- {
- out<<obj.t;
- return out;
- }
- };
- int main()
- {
- Increase i,ii,iii,iiii;
- ii=++i;
- cout<<ii<<endl;//i运行结果i=1;
- iiii=iii++;
- cout<<iiii<<endl;//运行结果iiii=0;
- }
8.=赋值号重载
赋值运算符重载用于对象数据的复制
operator= 必须重载为成员函数
重载函数原型为:
类名 & 类名 :: operator= ( 类名 )
#include<iostream>
#include<cstring>
using namespace std;
class Name
{ public :
Name (char *pN ) ;
Name( constName & ) ; //复制构造函数
Name&operator=( const Name& ) ; // 重载赋值运算符
~ Name() ;
protected :
char *pName ;
int size ;
} ;
int main()
{ Name Obj1( "ZhangSan" ) ;
Name Obj2 =Obj1 ; // 调用复制构造函数
Name Obj3("NoName" ) ;
Obj3 = Obj2 =Obj1 ; // 调用重载赋值运算符函数
}
STL
STL是由以下四部分组成的:
容器
迭代器
容器适配器
算法
容器、容器适配器和迭代器都是用类模板实现的,迭代器用于遍历容器中的每一个元素,算法用于操作数据。
容器
1. 容器即是可容纳一些数据的模板类,STL中包含vector/list/deque/set/map/multimap和multiset等容器。
(适配器就是接口,对容器、迭代器和算法进行包装、但其实质还是容器、迭代器和算法)。
2.容器的共同操作
初始化(initialization)
产生一个空容器
std::list<int>l;
以另一个容器元素为初值完成初始化
std::list<int>l;
…
std::vector<float> c(l.begin(),l.end());
以数组元素为初值完成初始化
intarray[]={2,4,6,1345};
…
std::set<int>c(array,array+sizeof(array)/sizeof(array[0]));
与大小相关的操作(size operator)
size()-返回当前容器的元素数量
empty()-判断容器是否为空
max_size()-返回容器能容纳的最大元素数量
比较(comparison)
==,!=,<,<=,>,>=
比较操作两端的容器必须属于同一类型
如果两个容器内的所有元素按序相等,那么这两个容器相等
采用字典式顺序判断某个容器是否小于另一个容器
赋值(assignment)和交换(swap)
swap用于提高赋值操作效率
迭代器(iterator)
可遍历STL容器内全部或部分元素的对象
指出容器中的一个特定位置
所有容器都提供两种迭代器
container::iterator以“读/写”模式遍历元素
container::const_iterator以“只读”模式遍历元素
begin()-返回一个迭代器,指向第一个元素
end()-返回一个迭代器,指向最后一个元素之后
rbegin()-返回一个逆向迭代器,指向逆向遍历的第一个元素
rend()-返回一个逆向迭代器,指向逆向遍历的最后一个元素之后
赋值(assignment)和交换(swap)
swap用于提高赋值操作效率
下面插入一段代码来介绍用vector创建容器
#include<iostream>
#include<vector>
#include<list>
#include<deque>
using namespace std;
int main()
{
vector<int>obv;
cout<<"obv的元素个数为:"<<obv.size()<<endl;
double sz[5]={1,2,3,4,5};
deque<double>obD(sz,sz+5);
for(unsigned int i=0;i<obD.size();i++)
{
cout<<obD[i]<<" ";
}
cout<<endl;
list<float>obL(3,5);
list<float>::iterator iter=obL.begin();
while(iter!=obL.end())
{
cout<<(*iter)<<" ";
iter++;
}
cout<<endl;
return 0;
}
vector的元素可以是任意类型T,但必须具备赋值和拷贝能力
必须包含的头文件#include <vector>
vector的大小(size)和容量(capacity)
size返回实际元素个数,
capacity返回vector能容纳的元素最大数量。
主要操作有:
①、v.size()返回当前v中元素个数;
②、v.push_back(i),将i添加到v的尾部;
③、v.erase(pos),删除迭代器pos所指向的元素;
容器迭代器对应的类型
容器 | 类内迭代器类别 |
vector | 随机访问迭代器 |
list | 双向迭代器 |
deque | 随机访问迭代器 |
map | 双向迭代器 |
multimap | 双向迭代器 |
set | 双向迭代器 |
multiset | 双向迭代器 |
3.map/multimap
使用map/multimap之前要加入头文件#include<map>,map和multimap将key/value当作元素,进行管理。它们可根据key的排序准则自动将元素排序。multimap允许重复元素,map不允许重复元素。