易码技术论坛

 找回密码
 加入易码
搜索
查看: 368648|回复: 6

[教程] C++中的重载

[复制链接]
发表于 2006-11-9 13:46:21 | 显示全部楼层
开始还以为你自己打了那么那么多字~要顶一下~
看到最后一行(转自.....)
发表于 2006-11-9 14:07:15 | 显示全部楼层
构造函数和析构函数支持重载么?
发表于 2006-11-9 15:05:16 | 显示全部楼层
支持!
 楼主| 发表于 2006-11-9 22:07:43 | 显示全部楼层
引用第2楼Cadina2006-11-09 14:07发表的“”:
构造函数和析构函数支持重载么?

构造函数可以,析构函数不可以。
因为析构函数没有参数,而且重载也无意义。
 楼主| 发表于 2006-11-10 00:31:19 | 显示全部楼层
引用第1楼不炫耀会死星人2006-11-09 13:46发表的“”:
开始还以为你自己打了那么那么多字~要顶一下~
看到最后一行(转自.....)

咳,只有下面那个要点是转载的啊
发表于 2006-11-10 12:26:49 | 显示全部楼层
引用第5楼shooting2006-11-10 00:31发表的“”:


咳,只有下面那个要点是转载的啊

呃....那什么~今天天气不错啊
 楼主| 发表于 2006-11-9 10:30:51 | 显示全部楼层 |阅读模式
好久没来了,最近异常忙乱,每天精神都比较疲惫~~这篇算是我那个教程的补充,等过了这一段我再继续连载那个。

一、函数重载:

所谓重载,就是一个名字能干多个事情。函数重载的意思就是,使用同一个函数名,可以定义不同的函数。
就像这样:
  1. int add( int a, int b);
  2. double add( double a, double b);
复制代码
使用同一个函数名add,我们定义了两个函数,分别对应整数的加法和双精度浮点数的加法,这样,在调用的使用,编译器会根据调用参数的不同自动选择要调用哪一个
  1. int c=add(10,20);
  2. double t=add(10.3,40.2);
复制代码

下面就有几个疑问
  1. int c=add(10.4,20.3);
  2. int d=add(10.3,20);
复制代码
这里的两个add会怎样调用呢?
对于第一个,它会调用double版本的,然后把结果转化为一个int。因为c++在判断该调用哪个重载的时候只看他的参数,而不会去理会他的返回值,由此也导致一件事情,就是参数类型完全相同,而返回值类型不同的时候是不会编译通过的。

对于第二个,你说该调用哪个呢?猜猜?
结果是哪个也不调用,编译器会抱怨不知道该怎么办,所以不要把代码写成这样。

在游戏设计中,一个很常见的行为就是画点,那么这个函数就可以被重载
  1. void DrawPoint(int x,int y);
  2. void DrawPoint(Point p);
复制代码

这样无论你使用分开的两个坐标,还是一个Point类型的变量,它都可以很好地被执行。
在实现上,对于一组完成相同功能的重载函数,一般会设定一个为主要函数,其他的尽量使用这个函数来完成,例如还是上面那个画点:
  1. void DrawPoint(int x, int y)
  2. {
  3.   //Your method to draw a point
  4.   //for example:
  5.   ::SetPixel(HDC,x,y);
  6. }
  7. void DrawPoint(Point p)
  8. {
  9.   //implement using the above function
  10.   DrawPoint(p.x,p.y)
  11. }
复制代码

这样可以保证最小的代码复制,提高了程序的健壮性,要知道,代码复制往往是恐怖的事情的开始。

二、运算符重载:

其实这个也是函数重载的一部分,不过由于它的特殊性,我把它单独列出来。

所谓运算符重载,在c++中的含义就是改变一个已经存在的运算符的意义,使它可以完成新的功能。要注意,c++中只能重载一个已经存在的运算符,并且只能赋予它新的意义,而不能改变它旧的意义,这一点一定要记住。

几乎所有的运算符都可以重载,目前只有.  .* :: :? 四个运算符不可以重载,那么可以重载的运算符就剩下:
    算术运算符:+ - * / % ++ --
  位操作运算符:& | ~ ^ << >>
  逻辑运算符:!  && ||
  比较运算符:< > >= <= == !=
  赋值运算符:=  +=  -=  *=  /=  %=  &=  |=  ^=  <<=  >>=
  其他运算符:[]  ()  ->  ,(逗号运算符)  new  delete  new[]  delete[]  ->*

如果没有玩过c++的人一定会被吓一跳,这么多运算符?其实这都不是全部,有时候类型转换也会被作为运算符加到这里面来。

不过这里我先按下复杂的不说,只讲讲最简单的几个关于算术操作的,先来看看加法吧。

作为一个运算符,我们一般会这样使用一个+
  1. a+b
复制代码
这样的话,其实我们可以把这个加法看作一个拥有两个参数的函数,它的返回值就是两个参数的和,就像上面提到的add,其实这个+的函数原型是这样的:
  1. int operator+(int a,int b);
  2. double operator+(double a,double b);
  3. .....
复制代码
c++为我们已经作了大量的重载,对于每一种基本类型,都定义了相关的operator+,可以让我们对他们使用+这个运算。那么对于我们自己的类型,定义的方式其实是一样的,下面我们定义一个复数类,它有两个成员。
  1. class Complex
  2. {
  3. public:
  4.   Complex(double r,double i)
  5.   :real(r),ime(i) //这个叫成员初始化列表,把要初始化的成员列在这里
  6.                //跟一个小括号中放它的初始值
  7.   {
  8.      
  9.   }
  10. public:
  11.   double real,ime;
  12. };
  13. [code]
  14. 他的加法应该这样定义:
  15. [code]
  16. //对于参数,这里使用常引用,这样可以保证c1,c2的值不会被改变
  17. //同时保证传递的时候不会发生拷贝
  18. //关于c++中的引用,请参见我前面写过的文章
  19. Complex operator+(const Complex& c1,const Complex& c2)
  20. {
  21.    return Complex(c1.real+c2.real, c1.ime+c2.ime);
  22. }
复制代码
这样,当你需要把两个复数相加的时候,就可以直接写了:
  1. Complex c1(10,20);
  2. Complex c2(2,4);
  3. Complex c3;
  4. c3=c1+c2;
复制代码

对于上面的代码,有一点需要解释,就是最后那句c3=c1+c2
编译器怎样知道应该怎么执行这个复值呢?它其实是自动把这个调用转化成了赋值运算符的调用,而我们又没有定义赋值运算符,所以编译器将使用位传送。对于c1+c2的运算结果,编译器将生成一个临时变量,然后将这个临时变量的值按位拷贝给c3。(当然,如果你暂时看不懂我说什么,就先放着吧)

学会了加法,你可以自己试试乘法和除法之类的,如果你使用过<iostream>的话,你对:
  1. cout<<a;
复制代码
一定不会陌生,这里其实就是ostream这个类型重载了他的<<运算符。

对于++和--,这里要讲一下。他们是一元运算符,所以我们一般将他们声明成类的成员
  1. class MyInt
  2. {
  3.   int v;
  4. public:
  5.   MyInt(int value) : value(v){}
  6.   MyInt operator++();
  7.   MyInt& operator++(int a);
  8. }
复制代码

有以下几点需要解释:
1、把运算符声明成成员,那么运算符的第一个操作数就是this,也就是对象本身
  1. class Complex
  2. {
  3. public:
  4.    double real,ime;
  5.    //这里作为成员,+的左操作数将作为函数的调用者
  6.    Complex operator+(const Complex& c2);
  7. };
  8. void main()
  9. {
  10.   Complex c1;
  11.   Complex c2;
  12.   c1+c2;//这里将调用c1.operator+(c2);
  13. }
复制代码
2、对于++的两种形式,一种是前缀,一种是后缀,这里使用一个假的参数来表示,没有参数的那个operator++将表示前缀的++,有参数的那个表示后缀的++
  1. Complex c1;
  2. c1++; //这里调用c1.operator++()
  3. ++c1;//这里调用c1.operator++(int)
复制代码
3、对于++两种是形式的不同返回值,是基于这样的考虑:
对于后缀的++,是先将对象的值返回,然后再把自己加一,那么返回的就必须是一个临时变量,而临时变量只可以使用传值操作。
对于前缀的++,则先++,再返回,这样就可以返回对象本身。
(这段看不懂就算了)

三、成员函数重载:

一个class中的成员函数也是可以重载的
  1. class Drawer
  2. {
  3.   void DrawPoint(int x,int y);
  4.   void DrawPoint(Point p);
  5. };
复制代码
其方法与函数重载并无二致,这里不再赘述。

四、小结:

对于c++的运算符重载,已经可以写一个很长的文章,甚至小册子了。这里只简要介绍几个比较简单的运算符。其实c++中的运算符重载应用十分广泛,有兴趣的人可以自己找书看看(前面不是有人推荐c++的书么)

另外从别人那里转几个要点:【转自http://www.yesky.com/406/1629406.shtml
1、运算符重载后,优先级和结合性怎么办?

  用户重载新定义运算符,不改变原运算符的优先级和结合性。这就是说,对运算符重载不改变运算符的优先级和结合性,并且运算符重载后,也不改变运算符的语法结构,即单目运算符只能重载为单目运算符,双目运算符只能重载双目运算符。

2、重载运算符有哪些限制?

  (1) 不可臆造新的运算符。必须把重载运算符限制在C++语言中已有的运算符范围内的允许重载的运算符之中。

  (2) 重载运算符坚持4个“不能改变”。

  ·不能改变运算符操作数的个数;
  ·不能改变运算符原有的优先级;
  ·不能改变运算符原有的结合性;
  ·不能改变运算符原有的语法结构。

3、运算符重载时必须遵循哪些原则?

  运算符重载可以使程序更加简洁,使表达式更加直观,增加可读性。但是,运算符重载使用不宜过多,否则会带来一定的麻烦。

  使用重载运算符时应遵循如下原则:

  (1) 重载运算符含义必须清楚。

  (2) 重载运算符不能有二义性。
您需要登录后才可以回帖 登录 | 加入易码

本版积分规则

Archiver|手机版|小黑屋|EMAX Studio

GMT+8, 2024-3-29 21:37 , Processed in 0.009240 second(s), 18 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表