重载运算符&STL




C++ 中的运算符重载

重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表。

Box operator+(const Box&);

声明加法运算符用于把两个 Box 对象相加,返回最终的 Box 对象。大多数的重载运算符可被定义为普通的非成员函数或者被定义为类成员函数。如果我们定义上面的函数为类的非成员函数,那么我们需要为每次操作传递两个参数,如下所示:

Box operator+(const Box&, const Box&);


可重载运算符/不可重载运算符
可重载
双目算术运算符+ (加),-(减),*(乘),/(除),% (取模)关系运算符==(等于),!= (不等于),< (小于),> (大于>,<=(小于等于),>=(大于等于)逻辑运算符||(逻辑或),&&(逻辑与),!(逻辑非)单目运算符+ (正),-(负),*(指针),&(取地址)自增自减运算符++(自增),--(自减)位运算符| (按位或),& (按位与),~(按位取反),^(按位异或),,<< (左移),>>(右移)赋值运算符=, +=, -=, *=, /= , % = , &=, |=, ^=, <<=, >>=空间申请与释放new, delete, new[ ] , delete[]其他运算符()(函数调用),->(成员访问),,(逗号),[](下标)

不可重载

.:成员访问运算符

.*, ->*:成员指针访问运算符

:::域运算符

sizeof:长度运算符

?::条件运算符

#: 预处理符号
一元运算符
一元运算符只对一个操作数进行操作
递增运算符( ++ )和递减运算符( -- )
一元减运算符,即负号( - )
逻辑非运算符( ! )
C++ 二元运算符重载
二元运算符需要两个参数,下面是二元运算符的实例。我们平常使用的加运算符( + )、减运算符( - )、乘运算符( * )和除运算符( / )都属于二元运算符。就像加(+)运算符。
下面的实例演示了如何重载加运算符( + )。类似地,您也可以尝试重载减运算符( - )和除运算符( / )。
实例
#include <iostream>
using namespace std;
 
class Box
{
   double length;      // 长度
   double breadth;     // 宽度
   double height;      // 高度
public:
 
   double getVolume(void)
   {
      return length * breadth * height;
   }
   void setLength( double len )
   {
       length = len;
   }
 
   void setBreadth( double bre )
   {
       breadth = bre;
   }
 
   void setHeight( double hei )
   {
       height = hei;
   }
   // 重载 + 运算符,用于把两个 Box 对象相加
   Box operator+(const Box& b)
   {
      Box box;
      box.length = this->length + b.length;
      box.breadth = this->breadth + b.breadth;
      box.height = this->height + b.height;
      return box;
   }
};
// 程序的主函数
int main( )
{
   Box Box1;                // 声明 Box1,类型为 Box
   Box Box2;                // 声明 Box2,类型为 Box
   Box Box3;                // 声明 Box3,类型为 Box
   double volume = 0.0;     // 把体积存储在该变量中
 
   // Box1 详述
   Box1.setLength(6.0); 
   Box1.setBreadth(7.0); 
   Box1.setHeight(5.0);
 
   // Box2 详述
   Box2.setLength(12.0); 
   Box2.setBreadth(13.0); 
   Box2.setHeight(10.0);
 
   // Box1 的体积
   volume = Box1.getVolume();
   cout << "Volume of Box1 : " << volume <<endl;
 
   // Box2 的体积
   volume = Box2.getVolume();
   cout << "Volume of Box2 : " << volume <<endl;
 
   // 把两个对象相加,得到 Box3
   Box3 = Box1 + Box2;
 
   // Box3 的体积
   volume = Box3.getVolume();
   cout << "Volume of Box3 : " << volume <<endl;
 
   return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:

Volume of Box1 : 210
Volume of Box2 : 1560
Volume of Box3 : 5400
C++ 关系运算符重载

C++ 语言支持各种关系运算符( < 、 > 、 <= 、 >= 、 == 等等),它们可用于比较 C++ 内置的数据类型。

您可以重载任何一个关系运算符,重载后的关系运算符可用于比较类的对象。

下面的实例演示了如何重载 < 运算符,类似地,您也可以尝试重载其他的关系运算符。

#include <iostream>
using namespace std;
 
class Distance
{
   private:
      int feet;             // 0 到无穷
      int inches;           // 0 到 12
   public:
      // 所需的构造函数
      Distance(){
         feet = 0;
         inches = 0;
      }
      Distance(int f, int i){
         feet = f;
         inches = i;
      }
      // 显示距离的方法
      void displayDistance()
      {
         cout << "F: " << feet << " I:" << inches <<endl;
      }
      // 重载负运算符( - )
      Distance operator- ()  
      {
         feet = -feet;
         inches = -inches;
         return Distance(feet, inches);
      }
      // 重载小于运算符( < )
      bool operator <(const Distance& d)
      {
         if(feet < d.feet)
         {
            return true;
         }
         if(feet == d.feet && inches < d.inches)
         {
            return true;
         }
         return false;
      }
};
int main()
{
   Distance D1(11, 10), D2(5, 11);
 
   if( D1 < D2 )
   {
      cout << "D1 is less than D2 " << endl;
   }
   else
   {
      cout << "D2 is less than D1 " << endl;
   }
   return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:

D2 is less than D1
C++ 输入/输出运算符重载

C++ 能够使用流提取运算符 >> 和流插入运算符 << 来输入和输出内置的数据类型。您可以重载流提取运算符和流插入运算符来操作对象等用户自定义的数据类型。

在这里,有一点很重要,我们需要把运算符重载函数声明为类的友元函数,这样我们就能不用创建对象而直接调用函数。

下面的实例演示了如何重载提取运算符 >> 和插入运算符 <<。

实例
#include <iostream>
using namespace std;
 
class Distance
{
   private:
      int feet;             // 0 到无穷
      int inches;           // 0 到 12
   public:
      // 所需的构造函数
      Distance(){
         feet = 0;
         inches = 0;
      }
      Distance(int f, int i){
         feet = f;
         inches = i;
      }
      friend ostream &operator<<( ostream &output, 
                                       const Distance &D )
      { 
         output << "F : " << D.feet << " I : " << D.inches;
         return output;            
      }
 
      friend istream &operator>>( istream  &input, Distance &D )
      { 
         input >> D.feet >> D.inches;
         return input;            
      }
};
int main()
{
   Distance D1(11, 10), D2(5, 11), D3;
 
   cout << "Enter the value of object : " << endl;
   cin >> D3;
   cout << "First Distance : " << D1 << endl;
   cout << "Second Distance :" << D2 << endl;
   cout << "Third Distance :" << D3 << endl;
 
 
   return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:

$./a.out
Enter the value of object :
70
10
First Distance : F : 11 I : 10
Second Distance :F : 5 I : 11
Third Distance :F : 70 I : 10
C++ ++ 和 -- 运算符重载

递增运算符( ++ )和递减运算符( -- )是 C++ 语言中两个重要的一元运算符。

下面的实例演示了如何重载递增运算符( ++ ),包括前缀和后缀两种用法。类似地,您也可以尝试重载递减运算符( -- )。

实例
#include <iostream>
using namespace std;
 
class Time
{
   private:
      int hours;             // 0 到 23
      int minutes;           // 0 到 59
   public:
      // 所需的构造函数
      Time(){
         hours = 0;
         minutes = 0;
      }
      Time(int h, int m){
         hours = h;
         minutes = m;
      }
      // 显示时间的方法
      void displayTime()
      {
         cout << "H: " << hours << " M:" << minutes <<endl;
      }
      // 重载前缀递增运算符( ++ )
      Time operator++ ()  
      {
         ++minutes;          // 对象加 1
         if(minutes >= 60)  
         {
            ++hours;
            minutes -= 60;
         }
         return Time(hours, minutes);
      }
      // 重载后缀递增运算符( ++ )
      Time operator++( int )         
      {
         // 保存原始值
         Time T(hours, minutes);
         // 对象加 1
         ++minutes;                    
         if(minutes >= 60)
         {
            ++hours;
            minutes -= 60;
         }
         // 返回旧的原始值
         return T; 
      }
};
int main()
{
   Time T1(11, 59), T2(10,40);
 
   ++T1;                    // T1 加 1
   T1.displayTime();        // 显示 T1
   ++T1;                    // T1 再加 1
   T1.displayTime();        // 显示 T1
 
   T2++;                    // T2 加 1
   T2.displayTime();        // 显示 T2
   T2++;                    // T2 再加 1
   T2.displayTime();        // 显示 T2
   return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:

H: 12 M:0
H: 12 M:1
H: 10 M:41
H: 10 M:42

C++ 函数调用运算符 () 重载

函数调用运算符 () 可以被重载用于类的对象。当重载 () 时,您不是创造了一种新的调用函数的方式,相反地,这是创建一个可以传递任意数目参数的运算符函数。

下面的实例演示了如何重载函数调用运算符 ()。

#include <iostream>using namespace std; class Distance{ private: int feet; // 0 到无穷 int inches; // 0 到 12 public: // 所需的构造函数 Distance(){ feet = 0; inches = 0; } Distance(int f, int i){ feet = f; inches = i; } // 重载函数调用运算符 Distance operator()(int a, int b, int c) { Distance D; // 进行随机计算 D.feet = a + c + 10; D.inches = b + c + 100 ; return D; } // 显示距离的方法 void displayDistance() { cout << "F: " << feet << " I:" << inches << endl; } };int main(){ Distance D1(11, 10), D2; cout << "First Distance : "; D1.displayDistance(); D2 = D1(10, 10, 10); // invoke operator() cout << "Second Distance :"; D2.displayDistance(); return 0;}当上面的代码被编译和执行时,它会产生下列结果:First Distance : F: 11 I:10Second Distance :F: 30 I:120
心得

1.除了类属关系运算符”.“、成员指针运算符”.*“、作用域运算符”::“、sizeof运算符和三目运算符”?:“以外,C++中的所有运算符都可以重载。
2.重载运算符限制在C++语言中已有的运算符范围内的允许重载的运算符之中,不能创建新的运算符。
3.运算符重载实质上是函数重载,因此编译程序对运算符重载的选择,遵循函数重载的选择原则。
4.运算符重载不能改变该运算符用于内部类型对象的含义。它只能和用户自定义类型的对象一起使用,或者用于用户自定义类型的对象和内部类型的对象混合使用时。
5.运算符重载是针对新类型数据的实际需要对原有运算符进行的适当的改造,重载的功能应当与原有功能相类似,避免没有目的地使用重载运算符。

C++ STL 教程C++ 标准模板库的核心包括以下三个组件:组件 描述容器(Containers) 容器是用来管理某一类对象的集合。C++ 提供了各种不同类型的容器,比如 deque、list、vector、map 等。算法(Algorithms) 算法作用于容器。它们提供了执行各种操作的方式,包括对容器内容执行初始化、排序、搜索和转换等操作。迭代器(iterators) 迭代器用于遍历对象集合的元素。这些集合可能是容器,也可能是容器的子集。这三个组件都带有丰富的预定义函数,帮助我们通过简单的方式处理复杂的任务。下面的程序演示了向量容器(一个 C++ 标准的模板),它与数组十分相似,唯一不同的是,向量在需要扩展大小的时候,会自动处理它自己的存储需求:实例关于上面实例中所使用的各种函数,有几点要注意:push_back( ) 成员函数在向量的末尾插入值,如果有必要会扩展向量的大小。size( ) 函数显示向量的大小。begin( ) 函数返回一个指向向量开头的迭代器。end( ) 函数返回一个指向向量末尾的迭代器。

vector

vector<T> c

产生空的vector

vector<T> c1(c2)

产生同类型的c1,并将复制c2的所有元素

vector<T> c(n)

利用类型T的默认构造函数和拷贝构造函数生成一个大小为nvector

vector<T> c(n,e)

 

产生一个大小为nvector,每个元素都是e

vector<T> c(beg,end)

产生一个vector,以区间[beg,end]为元素初值

 

非变动操作

操作

效果

c.size()

返回元素个数

c.empty()

判断容器是否为空

c.max_size()

返回元素最大可能数量(固定值)

c.capacity()

返回重新分配空间前可容纳的最大元素数量

c.reserve(n)

扩大容量为n

c1==c2

判断c1是否等于c2

c1!=c2

判断c1是否不等于c2

c1<c2

判断c1是否小于c2

c1>c2

判断c1是否大于c2

c1<=c2

判断c1是否大于等于c2

c1>=c2

判断c1是否小于等于c2

 

赋值操作

操作

效果

c1 = c2

c2的全部元素赋值给c1

c.assign(n,e)

将元素en个拷贝赋值给c

c.assign(beg,end)

将区间[beg,end]的元素赋值给c

c1.swap(c2)

c1c2元素互换

swap(c1,c2)

同上,全局函数

 

元素存取

操作

效果

at(idx)

返回索引idx所标识的元素的引用,进行越界检查

operator [](idx)

 

返回索引idx所标识的元素的引用,不进行越界检查

front()

返回第一个元素的引用,不检查元素是否存在

back()

 

返回最后一个元素的引用,不检查元素是否存在

 

迭代器相关函数

操作

效果

begin()

返回一个迭代器,指向第一个元素

end()

返回一个迭代器,指向最后一个元素之后

rbegin()

返回一个逆向迭代器,指向逆向遍历的第一个元素

rend()

返回一个逆向迭代器,指向逆向遍历的最后一个元素

 

安插元素

操作

效果

c.insert(pos,e)

pos位置插入元素e的副本,并返回新元素位置

c.insert(pos,n,e)

pos位置插入n个元素e的副本

c.insert(pos,beg,end)

pos位置插入区间[beg,end]内所有元素的副本

c.push_back(e)

在尾部添加一个元素e的副本

 

移除元素

操作

效果

c.pop_back()

移除最后一个元素但不返回最后一个元素

c.erase(pos)

删除pos位置的元素,返回下一个元素的位置

c.erase(beg,end)

删除区间[beg,end]内所有元素,返回下一个元素的位置

c.clear()

移除所有元素,清空容器

c.resize(num)

将元素数量改为num(增加的元素用defalut构造函数产生,多余的元素被删除)

c.resize(num,e)

 

将元素数量改为num(增加的元素是e的副本)

#include <iostream>
#include <vector>
using namespace std;
 
int main()
{
   // 创建一个向量存储 int
   vector<int> vec; 
   int i;
 
   // 显示 vec 的原始大小
   cout << "vector size = " << vec.size() << endl;
 
   // 推入 5 个值到向量中
   for(i = 0; i < 5; i++){
      vec.push_back(i);
   }
 
   // 显示 vec 扩展后的大小
   cout << "extended vector size = " << vec.size() << endl;
 
   // 访问向量中的 5 个值
   for(i = 0; i < 5; i++){
      cout << "value of vec [" << i << "] = " << vec[i] << endl;
   }
 
   // 使用迭代器 iterator 访问值
   vector<int>::iterator v = vec.begin();
   while( v != vec.end()) {
      cout << "value of v = " << *v << endl;
      v++;
   }
 
   return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:

vector size = 0
extended vector size = 5
value of vec [0] = 0
value of vec [1] = 1
value of vec [2] = 2
value of vec [3] = 3
value of vec [4] = 4
value of v = 0
value of v = 1
value of v = 2
value of v = 3
value of v = 4
set/multiset
使用平衡二叉树管理元素
集合(Set)是一种包含已排序对象的关联容器。
必须包含的头文件#include <set>
map容器是键-值对的集合,好比以人名为键的地址和电话号码。相反地,set容器只是单纯的键的集合。当我们想知道某位用户是否存在时,使用set容器是最合适的。

构造、拷贝和析构

操作

效果

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<c2

判断c1是否小于c2

c1>c2

判断c1是否大于c2

c1<=c2

判断c1是否大于等于c2

c1>=c2

判断c1是否小于等于c2

 

赋值

操作

效果

c1 = c2

c2的全部元素赋值给c1

c1.swap(c2) 

c1c2的元素互换

swap(c1,c2) 

同上,全局函数

 

特殊搜寻操作

操作

效果

count(key) 

返回键值等于key”的元素个数

find(key) 

返回键值等于key”的第一个元素,找不到返回end

lower_bound(key)

返回键值大于等于key”的第一个元素

upper_bound(key)

返回键值大于key”的第一个元素

equal_range(key)

返回键值等于key”的元素区间

 

迭代器相关函数

操作

效果

begin()

返回一个双向迭代器,指向第一个元素

end()

 

返回一个双向迭代器,指向最后一个元素之后

rbegin() 

返回一个逆向迭代器,指向逆向遍历的第一个元素

rend()

返回一个逆向迭代器,指向逆向遍历的最后一个元素

 

安插元素

操作

效果

c.insert(e) 

c.insert(beg,end) 

 

插入e的副本,并返回新元素位置

将区间[beg,end]内所有元素的副本插入到c

 

 

移除元素

操作

效果

c.erase(pos) 

删除迭代器pos所指位置的元素,无返回值

c.erase(val)

 

移除所有值为val的元素,返回移除元素个数

c.erase(beg,end) 

 

删除区间[beg,end]内所有元素,无返回值

c.clear() 

移除所有元素,清空容器

 

set中不允许key相同的元素,multiset允许key相同的元素
#include <set>
#include <iostream>
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;
}
//insert函数返回值是一个pair对象, 其first是被插入元素的迭代器,second代表是否成功插入了
输出:
1) 2.1 3.7 4.2 9.5
2) 9.5 not inserted

排序和查找算法
1)find
template<class InIt, class T>
InIt find(InIt first, InIt last, const T& val);
返回区间 [first,last) 中的迭代器 i ,使得 * i == val
排序和查找算法
2) find_if
template<class InIt, class Pred>
InIt find_if(InIt first, InIt last, Pred pr);
返回区间 [first,last) 中的迭代器 i, 使得 pr(*i) == true
3) binary_search 折半查找,要求容器已经有序且支持随机访问迭代器,返回是否找到
template<class FwdIt, class T>
 bool binary_search(FwdIt first, FwdIt last, const T& val);
上面这个版本,比较两个元素x,y 大小时, 看 x < y
template<class FwdIt, class T, class Pred>
bool binary_search(FwdIt first, FwdIt last, const T& val, Pred pr);
上面这个版本,比较两个元素x,y 大小时, 看 pr(x,y)
#include <vector>
#include <bitset>
#include <iostream>
#include <numeric>
#include <list>
#include <algorithm>
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";
 }
}
输出:
3) 9 found

4) lower_bound,uper_bound, equal_range
lower_bound:
 template<class FwdIt, class T>
FwdIt lower_bound(FwdIt first, FwdIt last, const T& val);
要求[first,last)是有序的,
查找大于等于val的最小的位置
upper_bound
template<class FwdIt, class T>
 FwdIt upper_bound(FwdIt first, FwdIt last, const T& val);
要求[first,last)是有序的,
查找大于val的最小位置
equal_range
template<class FwdIt, class T>
pair<FwdIt, FwdIt> equal_range(FwdIt first, FwdIt last, const T& val);
要求[first,last)是有序的,
返回值是一个pair, 假设为 p, 则
[first,p.first) 中的元素都比 val 小
[p.second,last)中的所有元素都比 val 大
5)sort   快速排序
template<class RanIt>
void sort(RanIt first, RanIt last);
按升序排序。判断x是否应比y靠前,就看 x < y 是否为true
template<class RanIt, class Pred>
void sort(RanIt first, RanIt last, Pred pr);
按升序排序。判断x是否应比y靠前,就看 pr(x,y) 是否为true
template<class FwdIt>
FwdIt  unique(FwdIt first, FwdIt last);
用 == 比较是否相等

改变序列的算法
template<class FwdIt, class Pred>
FwdIt  unique(FwdIt first, FwdIt last, Pred pr);
用 pr 比较是否等
去除[first,last) 这个升序序列中的重复元素
返回值是迭代器,指向元素删除后的区间的最后一个元素的后面
reverse
template<class BidIt>
void reverse(BidIt first, BidIt last);
颠倒区间[first,last)顺序

心得:
STL可以节省我们大量的时间,这样就不用让我们一一去构造函数了,而是一条语句就可以高效率实现我们想要实现的功能。STL容器就为我们提供了这样的方便,它允许我们重复利用已有的实现构造自己的特定类型下的数据结构,通过设置一些模板类,STL容器对最常用的数据结构提供了支持,这些模板的参数允许我们指定容器中元素的数据类型,可以将我们许多重复而乏味的工作简化。就图书管理系统来说,记录类中的记录数组可以用动态数组vector来代替普通数组r,按借书,还书时间来查找交易记录可以通过map/multimap来实现。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值