C++课程总结——重载运算符+STL

一、重载运算符:

1、知识点细化:重载运算符详细总结链接 https://blog.csdn.net/qq_41661919/article/details/80282121

2、知识再梳理:

首先,重载运算符一般有两种形式:第一种用成员函数的形式重载,第二种友元形式重载。

友元重载一般比成员函数重载要多一个参数,成员函数重载会通过this指针隐式传递对象本身的参数。。。

(一)其中,必须要用友元来重载的有:

①、输入输出流重载;

基本格式:

friend ostream & operator <<(ostream & output,Time & obj);
friend istream & operator >>(istream & input,Time & obj);
//最后的返回值为:return output; or return input;
其次,我们一般不在重载函数所输出的内容后面添加多余的空格或者换行,例如:
ostream & operator <<(ostream &output,Time & obj)
{
    output<<obj.month<<" ";
    output<<obj.day<<" ";
    output<<obj.hour<<" ";
    output<<obj.minute; //最后一个空格就不要了;
    return output;
}

(二)只能用成员函数形式重载的有:

①、[ ];

int & operator [] ( int i )//返回值为int型;
{
    return v[i] ;
}

        比如在vector中,我们通过重载[ ]来实现用下标来对容器内元素进行访问的功能,不过目前,重载[ ]还不是很常用,因为大多数情况下重载[]都已经被封装好了。

②、( );

        基本形式:

#include <iostream>
using namespace std ;
class  F
{
    public :
        double  operator ( )  ( double x ,  double  y ) ;
} ;

double  F :: operator ( )  ( double  x ,  double  y )
{
    return   x * x + y * y ;
}
int main ( )
{
    F  f  ;
    cout << f ( 5.2 , 2.5 ) << endl ;
}

        这就相当于写了一个求距离的函数,只不过原来的函数名变成了类名,原来通过使用函数名的方式调用普通函数对形参做运算,现在直接调用对象的成员函数来进行运算。

        另外,更常用的是,重载()给我们提供了一种自定义排序准则的方法,比如说STL中的map容器,有一种定义形式为:

map<Time, int, op>m1;

其中op为带有排序准则的 类(名) ;

具体如下(代码可能不完整,只是举例说明怎么使用):

struct op{
    const bool operator()(const Time &a, const Time &b){
        return (a.day < b.day);
    }
};

③、=(目前还没怎么用过);

Time  operator =(const int &x)
        {
            year=x;
            return *this;
        }
(三)还有即可用友元重载,又可以成员函数重载的例如比较运算(<、>,==......),还有++、--(注意前加与后加的不同:https://blog.csdn.net/qq_41661919/article/details/80282121等等。

目前比较常用的像重载<,其主要作用感觉还是为自定义排序规则服务;

具体形式例如时间类中(Time类中,用成员函数形式重载):

bool operator <(const Time &obj )const
{
    return year!=obj.year?year<obj.year:month!=obj.month?month<obj.month:day<obj.day;
}


二、STL容器:

        过去我们存储信息都是通过普通数组来实现,但其有一定的局限性,比如当数据量非常大时,查找或是删除等操作会变的很复杂且时间复杂度较高,所以C++在编写的时候为我们封装好了一些较实用的容器,例如queue、stack、multimap、vector等等。

下面总结目前几个经常使用的:

1、vector(动态数组):

目前所写的系统中,vector主要用于按原始顺序存储信息 ,主要操作有:

①、v.size()返回当前v中元素个数;

②、v.push_back(i),将i添加到v的尾部;

③、v.erase(pos),删除迭代器pos所指向的元素;

④、注意:vector <int> v,是定义了一个向量,而vector <int> v[10010]则是定义了一个向量数组,其中每一个元素都是一个单独的“数组”。

还有几个操作的易错点可以看一下下面这个程序及注释。。。

#include<bits/stdc++.h>
using namespace std;
vector <int> v;
vector <int>::iterator it;//iterator有读写两种功能、const_iterator只读;
int k=0;
int main()
{

    //for(int i=0;i<=6;++i)v[i]=i;  //该种方法无法给vector赋值,因为此时v的空间大小不确定;
    //for(it =v.begin();it<v.end();++it)v[i]=i;//同上;
    //v[0]=0;v[1]=1;v[2]=2......;//同上;
    for(int i=0;i<=6;++i)v.push_back(i);
    //for(int i=0;i<v.size();++i)cout<<v[i]<<endl;
    cout<<"打印方法①(通过迭代器打印):"<<endl;
    for(it =v.begin();it<v.end();++it)cout<<*it<<endl;//it是一个指针,直接cout<<it不可以;&it取地址,*it取内容;
    cout<<"打印方法②(通过下标输出):"<<endl;
    for(int i=0;i<v.size();++i)cout<<v[i]<<endl;
    cout<<"=============confine=============="<<endl;
    for(it =v.begin();it<v.end();++it)*it+=6;//iterator有读写两种功能;
    for(it =v.begin();it<v.end();++it)cout<<*it<<endl;
    cout<<"============================confine=================================="<<endl;
    cout<<"size:"<<v.size()<<endl;
    cout<<"max_size:"<<v.max_size()<<endl;
    cout<<"capacity:"<<v.capacity()<<endl;
    //for(int i=0;i<=8;++i)v[i]=i;错误,因为capacity现在最大为8;i只能<=7;
    cout<<"------capacity增大:"<<endl;
    v.reserve(101);
    cout<<"size:"<<v.size()<<endl;
    cout<<"max_size:"<<v.max_size()<<endl;
    cout<<"capacity:"<<v.capacity()<<endl;
    cout<<"empty:"<<v.empty()<<endl;
    cout<<"============================confine=================================="<<endl;
    swap(v[0],v[1]);
    //v[1].swap(v[0]);  //这样编译不过去,because it only operates two diffient vector(sunch as v and v2) ;
    cout<<v[0]<<" "<<v[1]<<endl;
    cout<<"============================confine=================================="<<endl;

    vector <int>v2;
    v2.assign(v.begin(),v.end());//不用考虑capacity的大小?好像不用;
    for(it =v2.begin();it<v2.end();++it)cout<<*it<<endl;
    cout<<"============================confine=================================="<<endl;




}

2、multimap;

        multimap常用作vector中存储内容的索引(元素的第二部分通常是其在vector中的位置),其最大的特点是可以根据元素的键值对元素进行自动排序,并且可以存储多个键值相同的元素。

常用操作:(以ATM用户操作类中对象数组的操作为例)

①、添加元素:

m1.insert(make_pair(string,int));//string 为对应存取钱类型,int为其在vector中位置;

②、删除单个元素:

m1.erase(pos);//pos为迭代器;

③、

m.lower_bound( key ):返回键值>=key的第一个元素位置;

m.upper_bound( key ):返回键值>key的第一个元素的位置;

特别注意它们的返回值是multimap类型的迭代器。

两者组合常用作查找对应键值的元素(比如查找所有存钱的信息并输出):

multimap < string,int > m1;
multimap < string,int >::iterator mit1;//map几乎所有操作都和迭代器有关;
for(mit1=lower_bound("cq");mit1!=upper_bound("cq");++mit1)
        cout<<v[mit1->second]<<endl;

④、注意:

1°:multimap中没有重载[ ],因此不能像map、vector一样通过“v[i],map[i]”的形式访问元素;

2°:如果要自定义排序准则,比如使用 multimap < string,int,op > m1; 的形式定义,一定注意op是类名,而不是函数名。


3、queue(先进先出、队列):

前段时间学习bfs时经常使用。。。

常用操作:

①、队尾添加元素:Q.push(x);

②、队首删除元素:Q.pop( );

③、队列是否为空:Q.empty( );

④、取队首元素:Q.front( );

⑤、补充优先队列(自动排序):

priority_queue <int,vector<int>,less<int> > Q;//从大到小排列  
priority_queue <int,vector<int>,greater<int> > Q;//从小到大排列

当然如果要排序的元素是复杂数据类型的话,就要用到重载了。。。


三、小心得:

        首先,从前面学习的递归、函数、类,再到现在的STL、重载,很容易发现它们都有一个或几个共同的特点,那就是使用它们能够使我们的程序更高效,可读性更强,所以就目前水平来说,“更好的程序”可以理解为就是运行速度更快,代码更简洁明了的程序。

        其次,对于重载来说,现阶段自己掌握的仅仅是使用重载对应运算符的模板(固定格式),但对于其中很多本质的东西,自己并不明白,例如在重载语句中,我们发现有多处使用了 “&”、“const”等符号或关键字,但这些东西为什么要加,不加对功能实现有没有影响,有影响的话又会有什么样的影响,对于这些问题,自己都不是特别的明白,当然,这也反映出自己的水平太low,确实在将来还有很多知识需要学习。

        最后,对于STL,目前来说只要会使用就可以了,上述自己不明白的那些语法细节可以暂时忽略,但对于各种容器及各种操作的“函数原型”我们还是要大概了解一下的,因为只用这样我们才能知道哪个位置该用哪种类型的数据,例如常用的v.erase( pos),括号中的部分应当是对应的迭代器,而不是所要删除的内容或者键值之类的,再如multimap中大部分的操作函数的返回值都是迭代器类型,因此我们在定义容器的同时也要为其定义一个对应类型的迭代器,然后通过迭代器和各种函数的组合使用来实现我们想要的功能。



  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值