C++特性 之 多态性

    多态是C++乃至面向对象中一个很重要的概念,也是大家学习中的难点,现在就我自己的理解写一些自己的学习心得:
    多态性是指对于类的某个功能如果输入的信息不同,那么得到的结果就会不一样;具体来说,就是对同一条消息,被不同类型的对象接收将产生不同的行为。
    在C++中,首先函数重载可以体现出多态性,也称为编译时的多态性,亦称静态联编。
    所谓静态联编,就是在编译阶段即将主调函数和函数体之间进行连接的联编成为静态联编。那么,和静态联编相对应的就是动态联编,也叫运行时的多态性。其在运行阶段有系统自动选择需要调用的函数体---虚函数。

   静态联编支持编译时多态,也称静态多态,它是通过运算符重载和函数重载实现的;动态联编支持运行时多态,也称动态多态,它是通过继承和虚函数实现的。如下例为静态联编实现:

Code:
  1. claas Student   
  2. {    
  3.    public:   
  4.      void print()   
  5.     {   
  6.       cout<<"A student"<<endl;   
  7.      }   
  8. };   
  9. class GStudent :public Student   
  10. {   
  11.   public:   
  12.      void print()   
  13.     {   
  14.       cout<<"A graduate"<<endl;   
  15.      }   
  16. };   
  17. int main()   
  18. {   
  19.   Student s1,*ps;   
  20.  GStudent s2;   
  21.  s1.print();   
  22.  s2.print();   
  23. s2.Student ::print();   
  24. ps=&s1;   
  25. ps ->print(); //基类指针和基类成员发生关联   
  26. ps=&s2;   
  27. ps->print(); //希望调用s2的输出函数,但调用的却是对象s1的输出函数   
  28. return 0;   
  29.   
  30. }  

   输出结果为:

Code:
  1.  A student   
  2. A graduate student   
  3. A student   
  4. A student   
  5. A student //在程序编译阶段,基类指针ps对print()的操作只能绑定到基类的print()上,导致输出了不期望的结果,而期望执行的是派生类的print()函数  


   虚函数定义: virtual 数据结构 函数名(形参表){函数体}
   说明:虚函数即是在函数定义时加上的虚化关键词;
   目的:为了能使系统最终实现多态联编。
  a>如果一个函数未被声明为虚函数,那么该函数一定采用动态联编。
  b>若一个函数声明为虚函数,该函数在调用时却不一定采用动态联编,即就是说讲一个函数声明为虚函数是采用动态联编的必要条件。
    动态联编的条件:(1)基类和派生类中存在两个函数名相同、参数个数相同、参数类型相同、返回值相同的成员函数。
                    (2)基类中的同名成员函数被虚化。
                    (3)基类指针指向派生类对象或基类引用去引用派生类对象。

  将上面代码中基类成员函数print()设为虚函数,并采用对象指针调用虚函数,便可实现动态联编。源代码如下:

Code:
  1. claas Student      
  2. {       
  3.    public:      
  4.      virtual  void print()  //定义虚函数    
  5.     {      
  6.       cout<<"A student"<<endl;      
  7.      }      
  8. };      
  9. class GStudent :public Student      
  10. {      
  11.   public:      
  12.     virtual  void print()   //此处关键字virtual可省略   
  13.     {      
  14.       cout<<"A graduate"<<endl;      
  15.      }      
  16. };      
  17. int main()      
  18. {      
  19.   Student s1,*ps;      
  20.   GStudent s2;      
  21.   s1.print();      
  22.   s2.print();      
  23.   s2.Student ::print();      
  24.   ps=&s1;      
  25.   ps ->print();     
  26.  ps=&s2;      
  27.   ps->print();  //对象指针调用虚函数,采用动态联编   
  28.   return 0;      
  29.      
  30. }     

该程序运行结果如下:

Code:
  1. A student   
  2. A graduate student   
  3. A student   
  4. A student   
  5. A graduate student  //该程序将基类的print函数声明为虚函数,可以达到预期目的,即定义一个基类的对象指针,根据类型兼容规则,就可以指向不同的派生对象,同时调用不同派生类的虚函数,这就是动态联编的结果。  

亦可将上例中基类的成员函数print()设为虚函数,采用对象引用调用函数,进而实现动态联编,源代码如下:

Code:
  1. claas Student         
  2. {          
  3.    public:         
  4.      virtual  void print()  //定义虚函数       
  5.     {         
  6.       cout<<"A student"<<endl;         
  7.      }         
  8. };         
  9. class GStudent :public Student         
  10. {         
  11.   public:         
  12.     virtual  void print()   //此处关键字virtual可省略      
  13.     {         
  14.       cout<<"A graduate"<<endl;         
  15.      }         
  16. };      
  17.   void main( Student &s )     //对象引用作参数   
  18.  {   
  19.    s.print();    //采用对象引用调用虚函数   
  20. }    
  21. int main()         
  22. {         
  23.   Student s1;         
  24.   GStudent s2;         
  25.   fun(s1);   
  26.   fun(s2);      
  27.   return 0;     
  28. }       

该程序运行的结果:

Code:
  1. A student   
  2. A graduate student  

综合以上运行结果表明:只要定义一个基类的对象指针或对象引用,就可以调用期望的虚函数。

以上纯属个人见解~~~如有不对之处,还望大家不吝赐教~~~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值