一、基础知识
(一)重载运算符:
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用好,真的会让代码的书写更加方便。但我在一些函数、算法的具体应用以及按条件构建所需容器时,还存在一些问题,还不够熟练,日后还需加强练习同时这一部分的学习,也启迪我,要善于利用网上的资源,查找自己不知道的东西,进行自学,了解更多的知识。