函数重载与STL总结

一、基础知识

(一)重载运算符:

1、运算符重载为成员函数

(1)声明与定义格式

类内声明:

class X

{

返回类型 operator运算符(形参表);

}

类外定义:

返回类型X::operator运算符(形参表)

{函数体}

(2)双目运算符重载为成员函数,形参表中只有一个参数,作为运算符的右操作数,当前对象作为左操作数,通过this指针隐式传递给函数。

实例:

#include<iostream>
using namespace std;
class Complex
{
public:
	Complex( )
	{real=0,imag=0;}
	Complex(double r,double i)
	{real=r; imag=i;}
	 Complex operator + (Complex &c2);
	void display( );
	private:
	   double real;
	   double imag;};

	   Complex Complex:: operator + (Complex &c2) {
	return Complex(real+c2.real, imag+c2.imag);}
 void Complex::display( ){
	cout<<"("<<real<<","<<imag<<"i)"<<endl;}
 int main(){
	Complex c1(3,4),c2(5,-10),c3;
	c3=c1+c2;
	cout<<"c1=";c1.display( );
	cout<<"c2=";c2.display( );
	cout<<"c1+c2 =";	c3.display( );
	return 0;

 }


用重载运算符加号来实现复数的加减,重载为成员函数,只有一个参数,代表右操作数,左操作数是对象本身。

(3)单目运算符重载为成员函数,参数表中没有参数,此时当前对象作为运算符的一个操作数。

实例:

#include<iostream>

using namespace std;
class Time
{
public:
		Time( ){minute=0;sec=0;}
		Time(int m,int s):minute(m),sec(s){ }
		Time operator++();
		Time operator++(int);
		void display()
		{
		    cout<<minute<<":"<<sec<<endl;
		}
		private:
		int minute;
		int sec;
};
Time Time::operator++( )
{
	if(++sec>=60)
	{
		sec-=60;
		++minute;
	}
	return *this;
}
Time Time::operator++(int)
{
	Time temp(*this);
	sec++;
	if(sec>=60)	{
		sec-=60;
		++minute;
	}
	return temp;
}
int main()
{
    Time t1(2,48);
    Time t2,t3;
    t2=++t1;
    t1.display();
    t2.display();
    t3=t1++;
    t1.display();
    t3.display();


}

无形参时代表前自增,返回自加后对象,有形参代表后自增,返回自加之前的对象。

2、用友元函数重载

(1)常用于运算符左右操作数类型不同的情形

在第一个函数需要隐式转换的情形下,使用友元函数重载

友元函数没有this指针时,所需操作数都需在参数表显示声明。

#include<iostream>
using namespace std;
class Complex
{ public:
      Complex( double r =0, double i =0 )
      { Real = r ;   Image = i ; }
      Complex(int a)
      { Real = a ;  Image = 0 ; }
      void print() const ;
   friend Complex operator+
   ( const Complex & c1, const Complex & c2 ) ;
   friend Complex operator-
   ( const Complex & c1, const Complex & c2 ) ;
   friend Complex operator-
   ( const Complex & c ) ;
  private:
      double  Real, Image ;
};
Complex operator + ( const Complex & c1, const Complex & c2 )
  { double r = c1.Real + c2.Real ;
  double i = c1.Image+c2.Image ;
     return Complex ( r,  i ) ;
  }
Complex operator - ( const Complex & c1, const Complex & c2 )
  { double r = c1.Real - c2.Real ;
  double i = c1.Image - c2.Image ;
     return Complex ( r,  i ) ;
  }
Complex operator- ( const Complex & c )
  { return Complex ( -c.Real, - c.Image ) ; }
void Complex :: print() const
  { cout << '(' << Real << " ," << Image << ')' << endl;}
   int main()
   {
	Complex c1(3,4),c2(5,-10),c3;
	c3=c1+c2;
	cout<<"c1=";
	c1.print( );
	cout<<"c2=";
	c2.print( );
	cout<<"c1+c2 =";
	c3.print( );
	return 0;

 }
用友元函数重载,做复数加减运算,左右操作数都需显示声明。

(2)与成员函数重载的区别

比成员函数少一个参数

操作数类型不同,必须友元重载

3常用重载函数应用:

(1)赋值运算符重载用于对象数据的复制

opertaor=必须重载为友元函数

重载函数原型

类名&类名::operator=类名

实例:

#include<iostream>
#include<cstring>
using namespace std;
class  Name
{ public :
     Name ( char  *pN ) ;
     Name( const Name & ) ;
     Name& operator=( const Name& ) ;
     ~ Name() ;
  protected :
     char  *pName ;
     int size ;
} ;

int main()
{ Name Obj1( "ZhangSan" ) ;
   Name Obj2 = Obj1 ;
   Name Obj3( "NoName" ) ;
   Obj3 = Obj2 = Obj1 ;
}
Name::Name ( char  *pN )
 { cout <<" Constructing " << pN << endl ;
    pName = new char[ strlen( pN ) + 1 ] ;
    if( pName != 0 ) strcpy( pName,pN ) ;
    size = strlen( pN ) ;
 }
Name::Name( const Name & Obj )	 //复制构造函数
{ cout << " Copying " << Obj.pName << " into its own block\n";
   pName = new char[strlen( Obj.pName ) + 1 ] ;
   if ( pName != 0 ) strcpy( pName, Obj.pName ) ;
   size = Obj.size;
}
Name & Name::operator= ( const Name & Obj )	 // 重载赋值运算符
{ delete  []pName ;
   pName = new char[ strlen( Obj.pName ) + 1 ] ;
   if ( pName != 0 ) strcpy( pName , Obj.pName ) ;
   size = Obj.size ;
   return *this ;
}
Name::~ Name()
{ cout << " Destructing " << pName << endl ;
   delete  []pName ;
   size = 0;
}

重载=与复制构造函数类似作用,但要注意复制构造函数是构造对象时调用,重载赋值运算符是对象构造完成后调用。

(2)重载运算符[]和()

是二元运算符,只能用成员函数重载。

[]下标运算符,访问数据对象的元素

 
 
#include<iostream>
using namespace std;
class  vector
{ public :
       vector ( int  n )
       {  v = new  int [ n ] ; size = n ; }
       ~ vector ( )
       { delete [ ] v ; size = 0 ; }
       int & operator [ ] ( int  i )
       {  return  v [ i ] ; }
   private :
       int * v ;
       int size ;
};
int main ( )
{  vector  a ( 5 ) ;
    a [ 2 ] = 12 ;
    cout << a [ 2 ] << endl ;
}

模拟动态数组,new int动态分配空间,重载下标运算符访问特定数据成员

()用于函数调用  格式:类型 类::operator()参数表

实例:

#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 ;
}

()可以看做调用函数,计算两个数的平方之和

(3)重载输入输出流(重点,常用)

重载输入输出流只能用友元

一般格式如下

重载输出流:

    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;

 }

实例:

#include<iostream>
#include<cstdlib>
using namespace std;
class vector
{ public :
     vector( int size =1 ) ;
     ~vector() ;
     int & operator[] ( int i ) ;
     friend ostream & operator << ( ostream & output , vector & ) ;
     friend istream & operator >> ( istream & input, vector & ) ;
  private :
     int * v ;
     int len ;
};
int main(){
   int k ;    cout << "Input the length of vector A :\n" ;
   cin >> k ;
  vector A( k ) ;    cout << "Input the elements of vector A :\n" ;
   cin >> A ;          cout << "Output the elements of vector A :\n" ;
  cout << A ;
}
vector::vector( int size )
{ if (size <= 0 || size > 100 )
    { cout << "The size of " << size << " is null !\n" ; exit( 0 ) ;  }
   v = new int[ size ] ;  len = size ;
}
vector :: ~vector() { delete[] v ;  len = 0 ; }
int & vector :: operator [] ( int i )
{ if( i >=0 && i < len )  return v[ i ] ;
  cout << "The subscript " << i << " is outside !\n" ;  exit( 0 ) ;
}
ostream & operator << ( ostream & output, vector & ary )
{ for(int i = 0 ; i < ary.len ; i ++ )
output << ary[ i ] << "  " ;
   output << endl ;
   return output ;
}
istream & operator >> ( istream & input, vector & ary )
{ for( int i = 0 ; i < ary.len ; i ++ )
input >> ary[ i ] ;
   return  input ;
}

还是一个模拟动态数组的过程,重载输入流来输入数组的元素,重载输出流来输出数组元素,重载下标运算符访问数据成员。

(二)STL

1、STL组件:

容器,迭代器,算法,容器适配器,函数对象。

(1)容器:

管理某类对象的集合,分为关联式容器(次序取决于插入时机位置)和序列式(取决于特定准则)

共同操作:

初始化、与大小相关的操作(size max_size() empty())、比较、赋值和交换、与迭代器相关的操作:(begin()、end()、rbegin()、rend())、元素操作(insert(pos,e)、erase(beg,end)、clear())

注意:begin()返回第一个元素,end()返回最后一个元素之后

(2)迭代器::iterator

遍历STL容器内全部或部分元素

指出容器内特定元素位置

迭代器分类:

双向迭代器、随机存取迭代器

2、vector

(1)基本概念:

vector模拟动态元素,元素可以是任意类型

必须包含头文件#include<vector>

vector支持随机存取

vector大小size(返回实际元素个数)和容量capacity(返回元素最大数量)

(2)实例分析:

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

int main(){
    vector<int> a;
    for (int i = 0; i < 5; ++i){
        a.push_back(5 - i);
    }
    cout << "Size: " << a.size() << endl;
    a.pop_back();
    a[0] = 1;

    cout << "Size: " << a.size() << endl;
    for (int i = 0; i < (int)a.size()-1; ++i){
        cout << a[i] << ", " ;
    }
    cout <<a[a.size()-1]<< endl;

    sort(a.begin(), a.end());
    cout << "Size: " << a.size() << endl;
    for (int i = 0; i < (int)a.size()-1; ++i){
        cout << a[i] << ", " ;
    }
    cout <<a[a.size()-1]<< endl;

    a.clear();
    cout << "Size: " << a.size() << endl;
    return 0;
}


建立一个vector容器a,push_back把数字5到1加入容器,a.size()输出元素个数,pop_back()去掉最后一个元素,sort(a.begin(),a.end())从开始到结束排序,a.clear()清空vector

3、map和multimap

(1)基本概念:

使用平衡二叉树管理,元素包括两部分(key,value),key是关键字,value是值,包含头文件#include<map>,map的key不同,multimap的key可以相同。

(2)实例分析:

#include <iostream>
#include <map>
#include <algorithm>
using namespace std;

struct T1{
    int v;
    bool operator<(const T1 &a)const{
        return (v < a.v);
    }
};

struct T2{
    int v;
};
struct cmp{
    const bool operator()(const T2 &a, const T2 &b){
        return (a.v < b.v);
    }
};

int main(){
   //map<T1, int>mt1; //example for user-defined class
    //map<T2, int, cmp>mt2; //example for user-defined class(functor)

    map<string, int> m2;
    map<string, int>::iterator m2i;
    //map<string, int, greater<string> >m2;
    //map<string, int, greater<string> >::iterator m2i, p1, p2;
    m2["abd"] = 2;
    m2["abc"] = 1;
    m2["cba"] = 2;
    m2.insert(make_pair("aaa", 9));
    m2["abf"] = 4;
    m2["abe"] = 2;
    cout << m2["abc"] << endl;

    m2i = m2.find("cba");
    if(m2i != m2.end()){
        cout << m2i->first<<":" <<m2i->second << endl;
    }else{
        cout << "find nothing" << endl;
    }

    cout << "Iterate" << endl;
    for(m2i = m2.begin(); m2i != m2.end(); m2i++){
        cout << m2i->first << ": " << m2i->second << endl;
    }

    return 0;
}

建立map ,m2,关键字为字符串类型,值为整数,为关键字赋值,建立迭代器m2i,m2i的位置为查找到“cba”的位置,输出时注意用指针分两部分输出,first输出关键字,second输出值。利用迭代器从头至尾遍历元素,输出元素两部分。

#include <iostream>
#include <map>
#include <algorithm>
using namespace std;

int main(){
    multimap<string, int> mm1;
    multimap<string, int>::iterator mm1i, p1, p2;
    mm1.insert(make_pair("b", 3));
    mm1.insert(make_pair("a", 0));
    mm1.insert(make_pair("b", 5));
    mm1.insert(make_pair("c", 4));
    mm1.insert(make_pair("b", 2));
    cout << "Size: " << mm1.size() << endl;
    for(mm1i = mm1.begin(); mm1i != mm1.end(); mm1i++){
        cout << mm1i->first << ": " << mm1i->second << endl;
    }

    cout << "COUNT: " << mm1.count("b") << endl;
    cout << "Bound: " << endl;
    p1 = mm1.lower_bound("b");
    p2 = mm1.upper_bound("b");
    for(mm1i = p1; mm1i != p2; mm1i++){
        cout << mm1i->first << ": " << mm1i->second << endl;
    }

    return 0;
}

multimap和map用法大致相似,但可以有相同的关键字,注意upper_bound返回大于等于关键字的第一个元素位置,lower_bound返回大于关键字的第一个元素位置

4、set、multiset、pair

(1)set、multiset基本概念

使用平衡二叉树管理,包含头文件#include<set>,set是单纯的键的集合,set不允许键相同,multiset允许。

(2)实例:

#include <iostream>
#include <set>
#include <algorithm>
using namespace std;

struct T1{
    int key;
    int value1, value2;
    bool operator<(const T1 &b)const{
        return (key < b.key);
    }
};

struct T2{
    int key;
    int v1, v2;
};
struct T2cmp{
    bool operator()(const T2 &a, const T2 &b){
        return (a.key < b.key);
    }
};

int main(){
    set<T1> s2;
   set<T2, T2cmp> s3;
//#if 1

    //set<string>s1;
    //set<string>::iterator iter1;
//#else
    set<string, greater<string> >s1;
    set<string, greater<string> >::iterator iter1;
   //# endif
    s1.insert("abc");
    s1.insert("abc");
    s1.insert("abc");
    s1.insert("bca");
    s1.insert("aaa");

    cout << "ITERATE:" << endl;
    for (iter1 = s1.begin(); iter1 != s1.end(); iter1++){
        cout << (*iter1) << endl;
    }

    cout << "FIND:" << endl;
    iter1 = s1.find("abc");
    if(iter1 != s1.end()) {
        cout << *iter1 << endl;
    }else{
        cout << "NOT FOUND" << endl;
    }

    return 0;
}


建立关键字字符串型的set,插入元素,建立迭代器,从头到尾遍历,输出元素值,再建立迭代器查找特定元素。

multiset类似,但可以有多个键相同的元素,在这里不再举例。

(3)pair生成key,value对

实例:

#include<bits/stdc++.h>
using namespace std;
main()  {
	typedef set<double,less<double> > double_set;
	const int SIZE = 5;
	double a[SIZE] = {2.1,4.2,9.5,2.1,3.7 };
	double_set doubleSet(a,a+SIZE);
	ostream_iterator<double> output(cout," ");
	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;
}

定义一个set类型的double_Set,用a数组初始化,ostream_iterator的作用是输出流,输出分隔符,copy是将一段范围内的元素复制到输出流中,insert返回一个pair对象p,第一部分值,第二部分是否插入,判断9.5是否插入.

5、算法

常用算法介绍:

count 计算一段范围内等于某个值的元素个数

count_if 计算一段范围内满足某个条件的元素个数

max_element 返回一段范围内最大元素的迭代器

for_each 遍历一段范围内的元素,调用函数

find 寻找特定元素第一次出现的位置,返回迭代器。

find_if 返回区间范围内满足制定条件的迭代器

binary_search折半查找,返回是否找到

lower_bound返回大于等于指定值的最小位置

upper_bound返回大于指定值的最小位置

sort快速排序,可以加一个条件形参,按条件排序

unique去重,返回迭代器,指向元素删除后区间最后一个元素后面

reverse 颠倒区间端点的顺序

#include <vector>
#include <bitset>
#include <iostream>
#include <numeric>
#include <list>
#include <algorithm>
#include<bits/stdc++.h>
using namespace std;
bool Greater10(int n)
{
	return n > 10;
}
main()  {
	const int SIZE = 10;
	int a1[] = { 2,8,1,50,3,100,8,9,10,2 };
	vector<int> v(a1,a1+SIZE);
	ostream_iterator<int> output(cout," ");
	vector<int>::iterator location;
	location = find(v.begin(),v.end(),10);
	if( location != v.end()) {
		cout << endl << "1) " << location - v.begin();
	}
	location = find_if( v.begin(),v.end(),Greater10);
	if( location != v.end())
		cout << endl << "2) " << location - v.begin();
		sort(v.begin(),v.end());
	if( binary_search(v.begin(),v.end(),9)) {
		cout << endl << "3) " << "9 found";
	}
}


条件n>10,建立动态vector v,用数组a初始化,寻找v中等于10的元素位置,寻找v中大于10的元素位置,对v排序,折半查找v中是否有9

二、心得体会:

在这一段时间学习过程中,我主要做的任务,是ATM模拟系统的设计,以及优化改进,在这过程中大量使用了重载和TL部分的知识,先说重载,通过重载输入输出,我实现了对象的整体输入与输出,取代了原来的display函数,使代码更加简洁,清晰,同时通过小于号重载,进行时间的比较,比我原来写的条件嵌套简单了很多,在写代码过程中,我们可以灵活运用重载,来实现自己想要的功能,让代码更加简洁,但在重载过程中,我还要注意成员函数和友元函数的区别,以及const的使用。再说STL,我用vector取代原有的对象数组,是数据存取更灵活,同时用multimap,对时间和类型进行查找,使代码行数更少,更加简洁,实际中,STL应用更多,我平常写ACM时,就需要用到很多STL的模板知识。STL用好,真的会让代码的书写更加方便。但我在一些函数、算法的具体应用以及按条件构建所需容器时,还存在一些问题,还不够熟练,日后还需加强练习同时这一部分的学习,也启迪我,要善于利用网上的资源,查找自己不知道的东西,进行自学,了解更多的知识。


猜你喜欢

转载自blog.csdn.net/sdauguanweihong/article/details/80428040
今日推荐