实验6,多态性与虚函数

一、实验目的和要求

    了解静态联编和动态联编的概念。掌握动态联编的条件。

二、实验内容

1、分析并调试下列程序。

   

[cpp]  view plain  copy
  1. //sy6_1.cpp  
  2. #include<iostream>  
  3. using namespace std;  
  4. class Base  
  5. {  
  6.     public:  
  7.         virtual void f(float x){cout<<"Base::f(float)"<<x<<endl;}  
  8.         void g(float x){cout<<"Base::g(float)"<<x<<endl;}  
  9.         void h(float x){cout<<"Base::h(float)"<<x<<endl;}  
  10. };  
  11. class Derived:public Base  
  12. {  
  13.     public:  
  14.         virtual void f(float x){cout<<"Derived::f(float)"<<x<<endl;}  
  15.         void g(float x){cout<<"Derived::g(float)"<<x<<endl;}  
  16.         void h(float x){cout<<"Derived::h(float)"<<x<<endl;}  
  17.   
  18. };  
  19. int main()  
  20. {  
  21.     Derived d;  
  22.     Base * pb=&d;  
  23.     Derived * pd=&d;  
  24.     pb->f(3.14f);  
  25.     pb->f(3.14f);  
  26.     pb->g(3.14f);  
  27.     pb->h(3.14f);  
  28.     pb->h(3.14f);  
  29.     return 0;  
  30. }  

(1)找出以上程序中使用了重载和覆盖的函数。

答:Base类中函数void g(); 和void h();与Derived类中的函数void g(); 和void h();函数名相同,参数类型不同,构成了函数重载。

(2)写出程序的输出结果,并解释输出结果。


2、分析并调试下列程序。

[cpp]  view plain  copy
  1. //sy6_2.cpp  
  2. #include<iostream>  
  3. using namespace std;  
  4. class Base  
  5. {  
  6.     public:  
  7.         void f(int x){cout<<"Base::f(int)"<<x<<endl;}  
  8.         void f(float x){cout<<"Base::f(float)"<<x<<endl;}  
  9.         virtual void g(void){cout<<"Base::g(void)"<<endl;}  
  10. };  
  11. class Derived:public Base  
  12. {  
  13.     public:  
  14.         virtual void g(void){cout<<"Derived::g(void)"<<x<<endl;}  
  15.   
  16. };  
  17. int main()  
  18. {  
  19.     Derived d;  
  20.     Base * pb=&d;  
  21.     Derived * pd=&d;  
  22.     pb->f(42);  
  23.     pb->f(3.14f);  
  24.     pb->g();  
  25.     return 0;  
  26. }  

(1)找出以上程序中使用了重载和覆盖的函数。

答:Base类中函数void f(); 在同一作用域中,函数名相同,参数类型不同,构成了函数重载。

(2)写出程序的输出结果,并解释输出结果。


3、分析并调试下列程序

[cpp]  view plain  copy
  1. //sy6_3.cpp  
  2. #include<iostream>  
  3. using namespace std;  
  4. class Point  
  5. {  
  6.     public:  
  7.         Point(double i,double j){x=i;y=j;}  
  8.         double Area(){return 0.0;}  
  9.     private:  
  10.         double x,y;  
  11.           
  12. };  
  13. class Rectangle:public Point  
  14. {  
  15.     public:  
  16.         Rectangle(double i,double j,double k,double l):Point(i,j){w=k;h=l;}  
  17.         double Area(){return w*h;}  
  18.     private:  
  19.         double w,h;  
  20.   
  21. };  
  22. int main()  
  23. {  
  24.     Point p(3.5,7);  
  25.     double A=p.Area();  
  26.     cout<<"Area="<<A<<endl;  
  27.     Rectangle r(1.2,3,5,7,8);  
  28.     A=r.Area();  
  29.     cout<<"Area="<<A<<endl;  
  30.     return 0;  
  31. }      
[cpp]  view plain  copy
  1. 写出程序的输出结果,并解释输出结果。  

4、分析并调试下列程序。

[cpp]  view plain  copy
  1. //sy6_4.cpp  
  2. #include<iostream>  
  3. using namespace std;  
  4. const double PI=3.1415;  
  5. class Shap  
  6. {  
  7.     public:  
  8.         virtual double Area()=0;  
  9.           
  10. };  
  11. class Triangle:public Shap  
  12. {  
  13.     public:  
  14.         Triangle(double h,double w){H=h;W=w;}  
  15.         double Area(){return 0.5*H*W;}  
  16.     private:  
  17.         double H,W;  
  18.   
  19. };  
  20. class Rectangle:public Shap  
  21. {  
  22.     public:  
  23.         Rectangle(double h,double w){H=h;W=w;}  
  24.         double Area(){return 0.5*H*W;}  
  25.     private:  
  26.         double H,W;  
  27. };  
  28. class Circle:public Shap  
  29. {  
  30.     public:  
  31.         Circle(double r){R=r;}  
  32.         double Area(){}return PI*R*R;}  
  33.     private:  
  34.         double R;  
  35. };  
  36. class Square:public Shap  
  37. {  
  38.     public:  
  39.         Square(double s){S=s;}  
  40.         double Area(){}return S*S;}  
  41.     private:  
  42.         double S;  
  43. };  
  44. double Total(Shap*s[],int n)  
  45. {  
  46.     double sum=0;  
  47.     for(int i=0;i<n;i++)  
  48.         sum+=s[i]->Area();  
  49.     return sum;  
  50. }  
  51. int main()  
  52. {  
  53.     Shap *s[5];  
  54.     s[0]=new Square(8.0);  
  55.     s[1]=new Square(3.0,8.0);  
  56.     s[2]=new Square(12.0);  
  57.     s[3]=new Square(8.0);  
  58.     s[4]=new Square(5.0,4.0);  
  59.     double sum=Total(s,5);  
  60.     cout<<"SUM="<<sum<<endl;  
  61.     return 0;  
  62. }  

运行结果:


(1)指出抽象类。

(2)指出纯虚函数,并说明它的作用。

(3)每个类的作用是什么?整个程序的作用是什么?

5. 某学校对教师每个月工资的计算规定如下:固定工资+课时补贴;教授的固定工资为5000元,每个课时补贴50;副教授的固定工资为3000,每个课时补贴30元;讲师的固定工资为2000元,每个课时补贴20元。定义教师抽象类,派生不同职称的教师类,编写程序求若干个教师的月工资。(sy6_5.cpp)

[cpp]  view plain  copy
  1. //sy6_5.cpp    
  2. #include <iostream>    
  3. using namespace std;    
  4. class Teacher    
  5. {    
  6. public:    
  7.     virtual int Salary()=0;    
  8.     virtual void Print(int)=0;    
  9. };    
  10.     
  11. class Professor:public Teacher    
  12. {    
  13. private:    
  14.     char name[128];    
  15.     int lessons;    
  16. public:    
  17.     Professor()    
  18.     {    
  19.         cout<<"请输入姓名:";    
  20.         cin>>name;    
  21.         cout<<"请输入课时:";    
  22.         cin>>lessons;    
  23.     };    
  24.     int Salary()    
  25.     {    
  26.         return (5000+lessons*50);    
  27.     };    
  28.     void Print(int money)    
  29.     {    
  30.         cout<<"职称:教授 姓名:"<<name<<" 薪水:"<<money<<endl<<endl;    
  31.     };    
  32. };    
  33.     
  34. class AssociateProfessor:public Teacher    
  35. {    
  36. private:    
  37.     char name[128];    
  38.     int lessons;    
  39. public:    
  40.     AssociateProfessor()    
  41.     {    
  42.         cout<<"请输入姓名:";    
  43.         cin>>name;    
  44.         cout<<"请输入课时:";    
  45.         cin>>lessons;    
  46.     };    
  47.     int Salary()    
  48.     {    
  49.         return (3000+lessons*30);    
  50.     };    
  51.     void Print(int money)    
  52.     {    
  53.         cout<<"职称:副教授 姓名:"<<name<<" 薪水:"<<money<<endl<<endl;    
  54.     };    
  55. };    
  56.     
  57. class Lecturer:public Teacher    
  58. {    
  59. private:    
  60.     char name[128];    
  61.     int lessons;    
  62. public:    
  63.     Lecturer()    
  64.     {    
  65.         cout<<"请输入姓名:";    
  66.         cin>>name;    
  67.         cout<<"请输入课时:";    
  68.         cin>>lessons;    
  69.     };    
  70.     int Salary()    
  71.     {    
  72.         return (2000+lessons*20);    
  73.     };    
  74.     void Print(int money)    
  75.     {    
  76.         cout<<"职称:讲师 姓名:"<<name<<"薪水:"<<money<<endl<<endl;    
  77.     };    
  78. };    
  79.     
  80. int main()    
  81. {    
  82.     Teacher *t = NULL;    
  83.     
  84.     int money=0;    
  85.     
  86.      t = new Professor();    
  87.     money = t->Salary();    
  88.     t->Print(money);    
  89.     delete t;    
  90.     
  91.     
  92.     t = new AssociateProfessor();    
  93.     money = t->Salary();    
  94.     t->Print(money);    
  95.     delete t;    
  96.     
  97.     
  98.     t = new Lecturer();    
  99.     money = t->Salary();    
  100.     t->Print(money);    
  101.     delete t;    
  102.     t = NULL;    
  103.     return 0;    
  104. }    

运行结果:


6. 把实验5中的第4题的Shape类定义为抽象类,提供共同操作界面的纯虚函数。TwoDimShape类和ThreeDimShape类仍然抽象类,第3层具体类才能提供全部函数的实现。在测试函数中,使用基类指针实现不同派生类对象的操作。

三、分析与讨论
1、结合实验内容中第1题和第2题,说明重载与覆盖的区别。
     答:重载与覆盖的区别:1、方法的覆盖是子类和父类之间的关系,是垂直关系;方法的重载是同一个类中方法之间的关系,是水平关系2、覆盖只能由一个方法,或只能由一对方法产生关系;方法的重载是多个方法之间的关系。3、覆盖要求参数列表相同;重载要求参数列表不同。4、覆盖关系中,调用那个方法体,是根据对象的类型(对象对应存储空间类型)来决定;重载关系,是根据调用时的实参表与形参表来选择方法体的。


2、总结静态联编和动态联编的区别和动态联编的条件。


  答:静态联编是指联编工作在编译阶段完成的,这种联编过程是在程序运行之前完成的,又称为早期联编。要实现静态联编,在编译阶段就必须确定程序中的操作调用(如函数调用)与执行该操作代码间的关系,确定这种关系称为束定,在编译时的束定称为静态束定。静态联编对函数的选择是基于指向对象的指针或者引用的类型。其优点是效率高,但灵活性差。
    动态联编是指联编在程序运行时动态地进行,根据当时的情况来确定调用哪个同名函数,实际上是在运行时虚函数的实现。这种联编又称为晚期联编,或动态束定。动态联编对成员函数的选择是基于对象的类型,针对不同的对象类型将做出不同的编译结果。C++中一般情况下的联编是静态联编,但是当涉及到多态性和虚函数时应该使用动态联编。动态联编的优点是灵活性强,但效率低。

       动态联编的条件:必须把动态联编的行为定义为类的虚函数;类之间应满足子类型关系,通常表现为一个类从另一个类公有派生而来;必须先使用基类指针指向子类型的对象,然后直接或者间接使用基类指针调用虚函数。

四、实验小结

    通过本次实验我们了解了静态联编和动态联编的概念,学习了动态联编的条件。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值