C++技术,愿与你分享

热爱C++,并且会越来越热爱她

关于C++中的多态性

多态性是面向对象的重要概念之一,但是当被问起什么是多态时,一般人都会含糊其辞。综合网上的阅览,笔者对这个概念作一个总结。

多态性的实现形式

  从广义上说,多态性是指一段程序能够处理多种类型对象的能力。在C++语言中,这种多态性可以通过强制多态(类型强制转换)、重载多态(函数及运算符重载)、类型参数化多态(模板)、包含多态(类继承及虚函数)四种形式来实现。类型参数化多态和包含多态统称为一般多态性,用来系统地刻画语义上相关的一组类型。重载多态和强制多态统称为特殊多态性,用来刻画语义上无关联的类型间的关系。

包含多态

  C++中采用虚拟函数实现包含多态,虚拟函数为C++提供了更为灵活的多态机制,这种多态性在程序运行时才能确定,因此虚拟函数是多态性的精华,至少含有一个虚拟函数的类称为多态类。包含多态在程序设计中使用十分频繁。
  派生类继承基类的所有操作,或者说,基类的操作能被用于操作派生类的对象,当基类的操作不能适应派生类时,派生类需重载基类的操作,见下例中的void circle::showarea()。

 1 #include <iostream.h>
 2    class  point  //屏幕上的点类
 3  { int  x,y;
 4     public
 5    point( int  x1, int  y1)
 6   {x=x1;y=y1;}
 7     void  showarea()
 8   {cout<<″Area of point  is :″<< 0.0 <<endl;}
 9   };
10
11    class  circle: public  point//圆类
12   { int  radius;
13     public
14    circle( int  x, int  y, int  r):point(x,y) { radius=r;}
15    void  showarea(){cout<<″Area of circle  is :″<< 3.14
16     * radius * radius<<endl;}
17   };
18
19    void  disparea( const  point * p) //多态程序段
20   {p->showarea();}
21    void  main()
22   {circle c1( 1 1 1 );disparea(&c1);
23   }
24
25


  程序的运行结果为0.0(正确结果应为3.14),出错的原因是:表达式p->showarea()中的函数调用在编译时被束定到函数体上,使得这个表达式中的函数调用执行point类的showarea()。为此,当程序员在实现一个派生类而变动了基类中的操作实现时,C++提供的虚函数机制可将这种变动告诉编译器,即将关键字virtual放在类point中该函数的函数说明之前(virtual void showarea()),程序其它部分保持不变(circle::showarea()自动地成为虚函数),编译器就不会对函数调用p->showarea()进行静态束定(在编译/连接时进行的束定)而产生有关的代码,使函数调用与它所应执行的代码的束定工作在程序运行时进行,这样上述程序的运行结果即为3.14。在程序运行时进行的束定被称为动态束定。
  利用虚函数,可在基类和派生类中使用相同的函数名定义函数的不同实现,从而实现“一个接口,多种方式”。当用基类指针或引用对虚函数进行访问时,软件系统将根据运行时指针或引用所指向或引用的实际对象来确定调用对象所在类的虚函数版本。

类型参数化多态

  参数化多态又称非受限类属多态,即将类型作为函数或类的参数,避免了为各种不同的数据类型编写不同的函数或类,减轻了设计者负担,提高了程序设计的灵活性。
  模板是C++实现参数化多态性的工具,分为函数模板和类模板二种。
  类模板中的成员函数均为函数模板,因此函数模板是为类模板服务的。类模板在表示数组、表、矩阵等类数据结构时,显得特别重要,因为这些数据结构的表示和算法的选择不受其所包含的元素的类型的影响。下面是一个通用数组类模板的定义。

1 template < class  T, int  N>
2    class  array
3   {T elem[N];
4     public
5    array(){ for ( int    j= 0 ;j<N;j ++ )elem[j]= 0 ;}
6    T&  operator []( int  index){ return  elem[index];}
7    void  modi( int  index,T value){elem[index]=value;}
8   };
9

  
  其中,T是类型参数,N是常量参数。T和N的实际值是在生成具体类实例时指定的。类模板的< >可以包括任意个类型参数或常量参数,但至少应有一个参数。在类模板定义中,可在程序中通常使用类型指定的任何地方使用类型参数,可在通常使用特定类型常量表达式的任何地方使用常量参数。

重载多态

   重载是多态性的最简形式,而且把更大的灵活性和扩展性添加到程序设计语言中,它分成操作符重载和函数重载。
  C++允许为类重定义已有操作符的语义,使系统预定义的操作符可操作类对象。C++语言的一个非常有说服力的例子是count对象的插入操作(<<)。由于其类中定义了对位左移操作符“<<”进行重载的函数,使C++的输出可按同一种方式进行,学习起来非常容易。并且,增加一个使其能输出复数类的功能(扩充)也很简单,不必破坏原输出逻辑。
  C++规定将操作符重载为函数的形式,既可以重载为类的成员函数,也可以重载为类的友员函数。用友员重载操作符的函数也称操作符函数,它与用成员函数重载操作符的函数不同,后者本身是类中成员函数,而它是类的友员函数,是独立于类的一般函数。注意重载操作符时,不能改变它们的优先级,不能改变这些操作符所需操作数的个数。
  重定义已有的函数称为函数重载。在C++中既允许重载一般函数,也允许重载类的成员函数。如对构造函数进行重载定义,可使程序有几种不同的途径对类对象进行初始化。还允许派生类的成员函数重载基类的成员函数,虚函数就属于这种形式的重载,但它是一种动态的重载方式,即所谓的“动态联编(束定)”。

强制多态

   强制也称类型转换。C++语言定义了基本数据类型之间的转换规则,即:
  char->short->int->unsigned->long->unsigned long->float->double->long double
  赋值操作是个特例,上述原则不再适用。当赋值操作符的右操作数的类型与左操作数的类型不同时,右操作数的值被转换为左操作数的类型的值,然后将转换后的值赋值给左操作数。
  程序员可以在表达式中使用3种强制类型转换表达式:①static_cast<T>(E);②T(E);③(T)E。其中任意一种都可改变编译器所使用的规则,以便按自己的意愿进行所需的类型强制。其中E代表一个运算表达式,T代表一个类型表达式。第三种表达形式是C语言中所使用的风格,在C++中,建议不要再使用这种形式,应选择使用第一种形式。例如,设对象f的类型为double,且其值为3.14。则表达式static_cast<int>(f)的值为3,类型为int。强制使类型检查复杂化,尤其在允许重载的情况下,导致无法消解的二义性,在程序设计时要注意避免由于强制带来的二义性。

posted on 2006-03-27 15:43 酷波波的C++技术博客 阅读(660) 评论(0)  编辑 收藏 引用 所属分类: C++基础


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