ivy-jie

progress ...

C++博客 首页 新随笔 联系 聚合 管理
  9 Posts :: 41 Stories :: 6 Comments :: 0 Trackbacks
 什么是操作符重载?
 一看到重载,很容易就让人联想到成员函数重载,函数重载可以使名称相同的函数具有不同的实际功能,只要赋给这些同名函数不同的参数就可以了,操作符重载也是基于这一机制的。系统为我们提供了许多操作符,比如“+”,“[ ]”等,这些操作符都有一些默认的功能,而操作符重载机制允许我们给这些操作符赋予不同的功能,并能够按照普通操作符的使用格式来使用自己定义功能的操作符(即重载的操作符)。
  定义之后,我们就可以按照平常使用操作符的格式来使用我们自己的重载操作符了。
  操作符重载一般在类内部定义,就像成员函数一样定义,这叫做类成员重载操作符。当然也可以在类外定义,即非类成员操作符重载。
  为什么要使用操作符重载?
  举例说明,比如类String,该类有这样一个功能,可以将两个字符串连接成一个字符串,为此,我们可以给类String定义一个成员函数实现此功能,可以给该函数取一个形象的名字,比如concatenate或append,但是相比较,这两个名字都不如操作符“+=”形象直观。在这种情况下,我们就可以定义操作符“+=”的重载,来实现此功能。
  也就是说,如果要定义一个函数,而这个函数的功能与操作符的功能比较类似时,这个时候我们就可以定义重载操作符,而不使用通常的成员函数定义。这里所说的操作符重载,指的是与系统定义的操作符重载,而不是说定义两个“+=”,这两个重载,这一点需要清楚。
  但是这四个操作符不能用于重载:   :: ,*, ?, :
  如何声明操作符重载?
  同普通函数类似,只不过它的名字包括关键字operator,以及紧随其后的一个预定义操作符。例如:
  String& operator+=(const String&);
  String& operator+=(const char*);
  注意:上面的括号表示形式参数,即使操作符重载不需要参数,也应该写上一个空的“( )”,而不是将其省略,这一点其实和普通函数的声明是类似的。其实,声明的唯一区别就是名字不同而已。
  怎样使用操作符重载?
  两种操作符重载:类成员操作符重载非类成员操作符重载
  1、类成员操作符重载
  已知类String中声明了两个“==”操作符重载,分别是:
  bool operator==(const char*) const;
  bool operator==(const String&) const;
  其中第一个重载的操作符允许我们比较一个String类对象是否等于一个C风格字符串,第二个允许我们比较两个String类对象是否相等。
  示例代码
  :
  #include<String.h>
  int main()
  {
  String flower;
  If(flower==”lily”) //正确:调用bool operator==(const char*) const;
  ……
  else
  if(“tulip”==flower) //错误
  …….
  }
  关键看一下,为什么第二个重载操作符的使用是错误的?
  因为:只有在左操作数是该类类型的对象时,才会考虑使用作为类成员的重载操作符。
  因为这里的”tulip”不是String类型对象,所以编译器试图找到一个内置操作符,它可以有一个C风格字符串的左操作数,然而事实上并不存在这样的操作符,所以编译时产生错误。
  疑问:我们可以使用String类的构造函数将一个C风格字符串,转换成一个String对象,为什么编译器不能做以上转换呢?即
  if(String(“tulip”)==flower);//这样就是正确的
  答:为了效率和正确性
  重载操作符并不要求两个操作数的类型一定相同。可能有这样一个类Text,这个类的构造函数的参数及其成员重载操作符的参数都与String类一致,如果使编译器能够自动将C风格字符串转换成某个类型的对象,那么编译器首先会检索所有的类定义,选择能够提供正确构造函数和重载操作符的类进行转换,这无疑会增加程序的编译时间,还有就是类String和类Text均合适,编译器也不知道该将C风格字符串转换成String还是Text对象了。
  对于类成员重载操作符,隐式的this指针被用作隐式的第一个参数,对于成员操作符,flower==”lily”会被编译器重写为:flower.operator==(“lily”);
  2、非类成员操作符重载
  为了解决上面的问题,我们可以考虑使用非类成员操作符代替类成员操作符,这样做的好处是左操作数不必非要是某个类的类型对象了,对于需要两个操作数的操作符重载,我们就可以定义两个参数了。比如:
  bool operator==(const String&,const String&);
  bool operator==(const String&,const char*);
  可以看到,这两个全局重载操作符比成员操作符多了一个参数,这样定义之后,还是上面的代码,当调用flower==”lily”时,会调用上面的bool operator==(const String&,const char*);
  然而“tulip”==flower会调用哪个操作符重载呢,我们并没有定义bool operator==(const char*,const String&);,我们是不是必须定义这样一个全局操作符重载呢?答案是否定的,因为当一个重载操作符是一个名字空间函数时,对于操作符的第一个和第二个参数,即等于操作符的左右两个操作数都会考虑转换,就像int vi=1; double vd=2.0; vi=vi+vd; 会先将vd转换成int型,再做加法一样这意味着,编译器将解释第二个用法如下:
  bool operator==(String(“tulip”),flower)。这样会增加系统转换开销。
  因此,如果需要频繁比较C风格字符串和String对象,那么最好定义上面的操作符重载,如果不频繁,我们只需定义下面一个就够了:
  bool operator==(const String&,const String&);
  什么时候定义类成员操作符重载,什么时候定义非类成员操作符重载?
  答:(1)如果一个重载操作符是类成员,那么只有当跟它一起使用的左操作数是该类对象时,它才会被调用,如果该操作符的左操作数必须是其他类型,那么重载操作符必须是非类成员操作符重载。
  (2)C++要求,赋值(=),下标([ ]),调用(())和成员访问箭头(->)操作符必须被指定为类成员操作符,否则错误。
posted on 2009-06-27 21:20 ivy-jie 阅读(519) 评论(0)  编辑 收藏 引用

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理