多态的实现(重载、虚函数、抽象类)

1.函数重载

由静态联编支持的多态性称为编译时的多态性或静态多态性,也就是说,确定同名操作的具体操作对象的过程是在编译过程中完成的。在C++中,可以用函数重载和运算符重载来实现编译时的多态性。

2.虚函数

由动态联编支持的多态性称为运行时的多太性或动态多态性,也就是说,确定同名操作的具体操作对象的过程是在运行过程中完成的。在C++中,可以用虚函数来实现运行时的多态性。

2.1.虚函数定义

虚函数的定义是在基类中进行的,即把基类中需要定义为虚函数的成员函数声明为virtual。当基类中的某个成员函数被声明为虚函数后,就可以在派生类中被重新定义。在派生类中重定义时,其函数原型,包括返回类型、函数函数名、参数个数和类型、参数的顺序都必须与基类中的原型完全一致

定义形式为:

  1. virtual <函数类型><函数名>(参数表)  
  2.   
  3. {  
  4.   
  5. 函数体  
  6.   
  7. }  

例如:解决博文多态概念时的问题代码如下:

  1. #include<iostream>  
  2. using namespace std;  
  3. class Animal  
  4. {  
  5.       public:  
  6.              void sleep()  
  7.              {  
  8.                   cout<<"Animal Sleep"<<endl;  
  9.                   }  
  10.             virtual void breathe()//加上virtual   
  11.              {  
  12.                   cout<<"Animal Breathe"<<endl;  
  13.                   }  
  14.       };  
  15. class Fish:public Animal  
  16. {  
  17.       public:  
  18.              void breathe()  
  19.              {  
  20.                   cout<<"Fish Bubble"<<endl;  
  21.                   }  
  22.       };  
  23. int main()  
  24. {  
  25.     Fish fs;  
  26.     Animal *an=&fs;  
  27.     an->breathe();  
  28.     system("pause");  
  29.     }  

只是加了一个virtual问题就解决了。输出结果为:

事实上,当将基类中的成员函数breathe()声明为virtual即虚函数时,编译器在编译的时候发现Animal类中有虚函数,此时编译器会为每个包含虚函数的类创建一个虚表,该表是一个一维数组,在这个数组中存放每个虚函数的地址。上述代码中,Animal类和Fish类都包含了一个虚函数breathe(),因此编译器会为这两个类分别建立一个虚表,如下图所示。

类Animal和类Fish的虚表

在上述代码中,当Fish类的fs对象构造完毕后,其内部的虚表指针也就被初始化为指向Fish类的虚表。在转换后,调用an->breathe(),由于an实际指向的是Fish类的对象,该对象内部的虚表指针指向的是Fish类的虚表,因此最终调用的是Fish类的breathe()函数。

使用派生对象指针时应注意的问题:

1.声明为指向基类对象的指针可以指向它的公有派生类的对象,但不允许指向它的私有派生类的对象。

2.允许声明为指向基类对象的指针指向它的公有派生类的对象,但不允许将一个声明为指向派生类对象的指针指向基类的对象。

3.声明为指向基类对象的指针,当其指向它的公有派生类的对象时(满足第1条),只能直接访问派生类中从基类继承下来的成员,不能直接访问公有派生类中定义的成员。要想访问其公有派生类中的成员,可将基类指针用显式类型转换方式转换为派生类指针。例如:

  1. #include<iostream>  
  2. using namespace std;  
  3. class B  
  4. {  
  5.       public:  
  6.              void vf()  
  7.              {  
  8.                   cout<<"This is class B"<<endl;  
  9.                   }  
  10.       };  
  11. class D:public B  
  12. {  
  13.       public:  
  14.              void vf()  
  15.              {  
  16.                   cout<<"This is class D"<<endl;  
  17.                   }  
  18.       };  
  19. int main()  
  20. {  
  21.     B b,*pb;  
  22.     D d,*pd;  
  23.     pb= &b;  
  24.     pb->vf();  
  25.     pb=&d;//满足第1第2条。   
  26.     pb->vf();  
  27.  // pd=&b;//违背第2条。invalid conversion from `B*' to `D*'   
  28.  // pd->vf();  
  29.     pd=(D*)&b;//满足第3条。   
  30.     pd->vf();  
  31.     pd=&d;  
  32.     pd->vf();  
  33.     system("pause");  
  34.     }  

如果把vf改成virtual类型的,有:

  1. #include<iostream>  
  2. using namespace std;  
  3. class B  
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值