详解C++编程中的单目运算符重载与双目运算符重载

 更新时间:2020年4月25日 17:37  点击:1942

C++单目运算符重载
单目运算符只有一个操作数,如!a,-b,&c,*p,还有最常用的++i和--i等。重载单目运算符的方法与重载双目运算符的方法是类似的。但由于单目运算符只有一个操作数,因此运算符重载函数只有一个参数,如果运算符重载函数作为成员函数,则还可省略此参数。

下面以自增运算符”++“为例,介绍单目运算符的重载。

[例] 有一个Time类,包含数据成员minute(分)和sec(秒),模拟秒表,每次走一秒,满60秒进一分钟,此时秒又从0开始算。要求输出分和秒的值。

#include <iostream>
using namespace std;
class Time
{
 public:
 Time( ){minute=0;sec=0;} //默认构造函数
 Time(int m,int s):minute(m),sec(s){ } //构造函数重载
 Time operator++( ); //声明运算符重载函数
 void display( ){cout<<minute<<":"<<sec<<endl;} //定义输出时间函数
 private:
 int minute;
 int sec;
};
Time Time::operator++( ) //定义运算符重载函数
{
 if(++sec>=60)
 {
  sec-=60; //满60秒进1分钟
  ++minute;
 }
 return *this; //返回当前对象值
}
int main( )
{
 Time time1(34,0);
 for (int i=0;i<61;i++)
 {
  ++time1;
  time1.display( );
 }
 return 0;
}

运行情况如下:

34:1
34:2
┆
34:59
35:0
35:1 (共输出61行)

可以看到:在程序中对运算符“++”进行了重载,使它能用于Time类对象。“++”和“--”运算符有两种使用方式,前置自增运算符和后置自增运算符,它们的作用是不一样的,在重载时怎样区别这二者呢?

针对“++”和“--”这一特点,C++约定,在自增(自减)运算符重载函数中,增加一个int型形参,就是后置自增(自减)运算符函数。

[例] 在上面例子程序的基础上增加对后置自增运算符的重载。修改后的程序如下:

#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 time1(34,59),time2;
 cout<<" time1 : ";
 time1.display( );
 ++time1;
 cout<<"++time1: ";
 time1.display( );
 time2=time1++; //将自加前的对象的值赋给time2
 cout<<"time1++: ";
 time1.display( );
 cout<<" time2 :";
 time2.display( ); //输出time2对象的值
}

请注意前置自增运算符“++”和后置自增运算符“++”二者作用的区别。前者是先自加,返回的是修改后的对象本身。后者返回的是自加前的对象,然后对象自加。请仔细分析后置自增运算符重载函数。

运行结果如下:

time1 : 34:59(time1原值)
++time1: 35:0 (执行++time1后time1的值)
time1++: 35:1 (再执行time1++后time1的值)
time2 : 35:0 (time2保存的是执行time1++前time1的值)

可以看到,重载后置自增运算符时,多了一个int型的参数,增加这个参数只是为了与前置自增运算符重载函数有所区别,此外没有任何作用。编译系统在遇到重载后置自增运算符时,会自动调用此函数。

C++双目运算符重载
双目运算符(或称二元运算符)是C++中最常用的运算符。双目运算符有两个操作数,通常在运算符的左右两侧,如3+5,a=b,i<10等。在重载双目运算符时,不言而喻在函数中应该有两个参数。

[例] 定义一个字符串类String,用来存放不定长的字符串,重载运算符“==”、“<”和“>”,用于两个字符串的等于、小于和大于的比较运算。

为了使读者便于理解程序,同时也使读者了解建立程序的步骤,下面分几步来介绍编程过程:
1) 先建立一个String类:

#include <iostream>
using namespace std;
class String
{
 public:
 String( ){p=NULL;} //默认构造函数
 String(char *str); //构造函数
 void display( );
 private:
 char *p;//字符型指针,用于指向字符串
};
String::String(char *str) //定义构造函数
{p=str;} //使p指向实参字符串
void String::display( ) //输出p所指向的字符串
{cout<<p;}
int main( )
{
 String string1("Hello"),string2("Book");
 string1.display( );
 cout<<endl;
 string2.display( );
 return 0;
}

运行结果为:

Hello
Book

2) 有了这个基础后,再增加其他必要的内容。现在增加对运算符重载的部分。为便于编写和调试,先重载一个运算符“>”。程序如下:

#include <iostream>
#include <string>
using namespace std;
class String
{
  public:
  String( ){p=NULL;}
  String(char *str);
  friend bool operator>(String &string1,String &string2);//声明运算符函数为友元函数
  void display( );
  private:
  char *p;//字符型指针,用于指向字符串
};
String::String(char *str)
{p=str;}
void String::display( ) //输出p所指向的字符串
{cout<<p;}
bool operator>(String &string1,String &string2)//定义运算符重载函数
{
  if(strcmp(string1.p,string2.p)>0)
   return true;
  else return false;
}
int main( )
{
  String string1("Hello"),string2("Book");
  cout<<(string1>string2)<<endl;
}

程序运行结果为1。

这只是一个并不很完善的程序,但是,已经完成了实质性的工作了,运算符重载成功了。其他两个运算符的重载如法炮制即可。

3) 扩展到对3个运算符重载。
在String类体中声明3个成员函数:
 

 friend bool operator> (String &string1, String &string2);
 friend bool operator< (String &string1, String &string2);
 friend bool operator==(String &string1, String& string2);

在类外分别定义3个运算符重载函数:

bool operator>(String &string1,String &string2) //对运算符“>”重载
{
 if(strcmp(string1.p,string2.p)>0)
  return true;
 else
  return false;
}
bool operator<(String &string1,String &string2) //对运算符“<”重载
{
 if(strcmp(string1.p,string2.p)<0)
  return true;
 else
  return false;
}
bool operator==(String &string1,String &string2) //对运算符“==”重载
{
 if(strcmp(string1.p,string2.p)==0)
  return true;
 else
  return false;
}

再修改主函数:

int main( )
{
 String string1("Hello"), string2("Book"), string3("Computer");
 cout<<(string1>string2)<<endl; //比较结果应该为true
 cout<<(string1<string3)<<endl; //比较结果应该为false
 cout<<(string1==string2)<<endl; //比较结果应该为false
 return 0;
}

运行结果为:

1
0
0


结果显然是对的。到此为止,主要任务基本完成。

4) 再进一步修饰完善,使输出结果更直观。下面给出最后的程序。

#include <iostream>
using namespace std;
class String
{
 public:
 String( ){p=NULL;}
 String(char *str);
 friend bool operator>(String &string1, String &string2);
 friend bool operator<(String &string1, String &string2);
 friend bool operator==(String &string1, String &string2);
 void display( );
 private:
 char *p;
};
String::String(char *str)
{p=str;}
void String::display( ) //输出p所指向的字符串
{cout<<p;}
bool operator>(String &string1, String &string2)
{
 if(strcmp(string1.p, string2.p)>0)
  return true;
 else
  return false;
}
bool operator<(String &string1, String &string2)
{
 if(strcmp(string1.p, string2.p)<0)
  return true;
 else
  return false;
}
bool operator==(String &string1, String &string2)
{
 if(strcmp(string1.p, string2.p)==0)
  return true;
 else
  return false;
}
void compare(String &string1, String &string2)
{
 if(operator>(string1, string2)==1)
  {string1.display( );cout<<">";string2.display( );}
 else
  if(operator<(string1, string2)==1)
   {string1.display( );cout<<"<";string2.display( );}
  else
   if(operator==(string1, string2)==1)
   {string1.display( );cout<<"=";string2.display( );}
 cout<<endl;
}
int main( )
{
 String string1("Hello"), string2("Book"), string3("Computer"), string4("Hello");
 compare(string1, string2);
 compare(string2, string3);
 compare(string1, string4);
 return 0;
}

运行结果为:

Hello>Book
Book<Computer
Hello==Hello

增加了一个compare函数,用来对两个字符串进行比较,并输出相应的信息。这样可以减轻主函数的负担,使主函数简明易读。

通过这个例子,不仅可以学习到有关双目运算符重载的知识,而且还可以学习怎样去编写C++程序。由于C ++程序包含类,一般都比较长,有的初学C++的读者见到比较长的程序就发怵,不知该怎样着手去阅读和分析它。轮到自己编程序,更不知道从何入 手,往往未经深思熟虑,想到什么就写什么,一口气把程序写了出来,结果一运行,错 误百出,光为找出错位置就花费了大量的时间。根据许多初学者的经验,上面介绍的方法是很适合没有编程经验的初学者的,能使人以清晰的思路进行程序设计,减少出错机会, 提高调试效率。

这种方法的指导思想是:先搭框架,逐步扩充,由简到繁,最后完善。边编程,边调试,边扩充。千万不要企图在一开始时就解决所有的细节。类是可扩充的,可以一步一步地扩充它的功能。最好直接在计算机上写程序,每一步都要上机调试,调试通过了前面一步再做下一步,步步为营。这样编程和调试的效率是比较高的。大家可以试验一下。

[!--infotagslink--]

相关文章

  • C++ STL标准库std::vector的使用详解

    vector是表示可以改变大小的数组的序列容器,本文主要介绍了C++STL标准库std::vector的使用详解,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2022-03-06
  • C++中取余运算的实现

    这篇文章主要介绍了C++中取余运算的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-23
  • 详解C++ string常用截取字符串方法

    这篇文章主要介绍了C++ string常用截取字符串方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • C++调用C#的DLL程序实现方法

    本文通过例子,讲述了C++调用C#的DLL程序的方法,作出了以下总结,下面就让我们一起来学习吧。...2020-06-25
  • C++中四种加密算法之AES源代码

    本篇文章主要介绍了C++中四种加密算法之AES源代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。...2020-04-25
  • C++ 整数拆分方法详解

    整数拆分,指把一个整数分解成若干个整数的和。本文重点给大家介绍C++ 整数拆分方法详解,非常不错,感兴趣的朋友一起学习吧...2020-04-25
  • C++中 Sort函数详细解析

    这篇文章主要介绍了C++中Sort函数详细解析,sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变...2022-08-18
  • C++万能库头文件在vs中的安装步骤(图文)

    这篇文章主要介绍了C++万能库头文件在vs中的安装步骤(图文),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-23
  • 详解C++ bitset用法

    这篇文章主要介绍了C++ bitset用法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • 浅谈C++中的string 类型占几个字节

    本篇文章小编并不是为大家讲解string类型的用法,而是讲解我个人比较好奇的问题,就是string 类型占几个字节...2020-04-25
  • C++ Eigen库计算矩阵特征值及特征向量

    这篇文章主要为大家详细介绍了C++ Eigen库计算矩阵特征值及特征向量,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-04-25
  • C++ pair的用法实例详解

    这篇文章主要介绍了C++ pair的用法实例详解的相关资料,需要的朋友可以参考下...2020-04-25
  • VSCode C++多文件编译的简单使用方法

    这篇文章主要介绍了VSCode C++多文件编译的简单使用方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-03-29
  • C++中的循环引用

    虽然C++11引入了智能指针的,但是开发人员在与内存的斗争问题上并没有解放,如果我门实用不当仍然有内存泄漏问题,其中智能指针的循环引用缺陷是最大的问题。下面通过实例代码给大家介绍c++中的循环引用,一起看看吧...2020-04-25
  • C++随机点名生成器实例代码(老师们的福音!)

    这篇文章主要给大家介绍了关于C++随机点名生成器的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • C++如何删除map容器中指定值的元素详解

    map容器是C++ STL中的重要一员,删除map容器中value为指定元素的问题是我们经常与遇到的一个问题,下面这篇文章主要给大家介绍了关于利用C++如何删除map容器中指定值的元素的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。...2020-04-25
  • C++ 约瑟夫环问题案例详解

    这篇文章主要介绍了C++ 约瑟夫环问题案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下...2021-08-15
  • C++中cin的用法详细

    这篇文章主要介绍了C++中cin的用法详细,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • 基于C++中常见编译错误的总结详解

    本篇文章是对C++中的常见编译错误进行了详细的分析介绍,需要的朋友参考下...2020-04-25
  • c++优先队列(priority_queue)用法详解

    这篇文章主要介绍了c++优先队列(priority_queue)用法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25