实验6 多态性与虚函数(P285)

本文通过几个具体的C++程序实例,介绍了静态联编与动态联编的概念及区别,重点探讨了动态联编的实现条件,并通过实验加深了对重载与覆盖函数的理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

实验目的和要求

     了解静态联编的动态联编的概念。掌握动态联编的条件。
实验内容
1.分析并调试下列程序。
[cpp]  view plain  copy
  1. #include<iostream>  
  2. using namespace std;  
  3. class Base  
  4.  public:  
  5.         virtual void f(float x){cout<<"Base::f(float)"<<x<<endl;}    
  6.         void g(float x){cout<<"Base::g(float)"<<x<<endl;}    
  7.        void h(float x){cout<<"Base::h(float)"<<x<<endl;}  
  8. };   
  9. class Derived:public Base  
  10. {  
  11.     public:    
  12.         virtual void f(float x){cout<<"Derived::f(float}"<<x<<endl;}    
  13.       void g(int x){cout<<"Derived::g(int)"<<x<<endl;}  
  14.       void h(float x){cout<<"Derived::h(float)"<<x<<endl;}  
  15. int main()    
  16. {  
  17.     Derived d;  
  18.     Base *pb=&d;   
  19.    Derived *pd=&d;  
  20.    pb->f(3.14f);   
  21.     pd->f(3.14f);    
  22.    pb->g(3.14f);</span>    
  23.    pb->h(3.14f);</span>    
  24.    pd->h(3.14f);</span>    
  25.     return 0;</span>    
  26. }  

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

(2)写出程序的输出结果,并解释输出结果。
程序的输出结果如下:
2 . 分析并调试下列程序
[cpp]  view plain  copy
  1. #include<iostream>  
  2. using namespace std;  
  3. class Base  
  4. {  
  5.     public:  
  6.         void f(int x){cout<<"Base::f(int)"<<x<<endl;}  
  7.         void f(float x){cout<<"Base::f(float)"<<x<<endl;}  
  8.         virtual void g(void){cout<<"Base::g(void)"<<endl;}  
  9. };  
  10. class Derived:public Base  
  11. {  
  12.     public:  
  13.         virtual void g(void){cout<<"Derived::g(void}"<<endl;}  
  14. };  
  15. int main()  
  16. {  
  17.     Derived d;  
  18.     Base *pb=&d;  
  19.     pb->f(42);  
  20.     pb->f(3.14f);  
  21.     pb->g();  
  22.     return 0;  
  23. }  


}(1)找出以上程序中使用了重载和覆盖函数。
(2)写出程序的输出结果,并解释输出结果。
程序的输出结果如下:
3. 分析并调试下列程序
[cpp]  view plain  copy
  1. #include<iostream>    
  2. using namespace std;    
  3. class Point    
  4. {    
  5.     public:    
  6.         Point(double i,double j){x=i;y=j;}    
  7.         double Area(){return 0.0;}    
  8.     private:    
  9.         double x,y;    
  10. };    
  11. class Rectangle:public Point    
  12. {    
  13.     public:    
  14.         Rectangle(double i,double j,double k,double l):Point(i,j){w=k;h=l;}    
  15.         double Area(){return w*h;}    
  16.     private:    
  17.         double w,h;    
  18. };    
  19. int main()    
  20. {    
  21.     Point p(3.5,7);    
  22.     double A=p.Area();    
  23.     cout<<"Area= "<<A<<endl;    
  24.     Rectangle r(1.2,3,5,7.8);    
  25.     A=r.Area();    
  26.     cout<<"Area= "<<A<<endl;    
  27.     return 0;    
  28. }  



写出程序的输出结果,并解释输出结果。
程序的输出结果如下:

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


程序的输出结果如下:
(1)指出抽象类。
(2)指出纯虚函数,并说明它的作用。
(3)每个类的作用是什么?整个程序的作用是什么?

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

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


程序输出结果如下:

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

分析与讨论
1.结合实验内容中第1题和第2题,说明重载与覆盖的区别。

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

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

  答:静态联编是指联编工作在编译阶段完成的,这种联编过程是在程序运行之前完成的,又称为早期联编。要实现静态联编,在编译阶段就必须确定程序中的操作调用(如函数调用)与执行该操作代码间的关系,确定这种关系称为束定,在编译时的束定称为静态束定。静态联编对函数的选择是基于指向对象的指针或者引用的类型。其优点是效率高,但灵活性差。

   动态联编是指联编在程序运行时动态地进行,根据当时的情况来确定调用哪个同名函数,实际上是在运行时虚函数的实现。这种联编又称为晚期联编,或动态束定。动态联编对成员函数的选择是基于对象的类型,针对不同的对象类型将做出不同的编译结果。C++中一般情况下的联编是静态联编,但是当涉及到多态性和虚函数时应该使用动态联编。动态联编的优点是灵活性强,但效率低。

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

实验总结

  通过本次实验我了解静态联编的动态联编的概念以及静态联编和动态联编的区别,了解了什么是重载和覆盖函数掌握动态联编的条件

多态性是面向对象编程中的一个重要概念,它允许不同的对象对同一个消息做出不同的响应。在C++中,通过虚函数实现多态性。在引用中的第一个程序中,定义了一个基ONE和两个派生TWO和THREE。基ONE中定义了一个虚函数f(),派生TWO和THREE都对该虚函数进行了重写。在main函数中,通过指针p调用了基ONE和派生THREE中的f()函数。由于f()函数是虚函数,在运行时会根据指针的实际型来确定调用哪个版本的f()函数。因此,在p指向派生THREE的对象时,调用的是派生THREE中的f()函数。这就是多态性的体现。中的程序二中,定义了一个基Base和一个派生SubClass。基Base中定义了一个虚函数fn(),派生SubClass对该虚函数进行了重写。在main函数中,通过指针p分别调用了基Base和派生SubClass中的fn()函数。同样地,由于fn()函数是虚函数,在运行时会根据指针的实际型来确定调用哪个版本的fn()函数。因此,当p指向派生SubClass的对象时,调用的是派生SubClass中的fn()函数。这也是多态性的一种表现形式。中的程序中,定义了一个A和一个派生B。A中有两个私有的整型变量a和b,并定义了构造函数进行初始化,以及成员函数geta()和getb()来获取a和b的值。派生B从A继承并覆盖了geta()函数,使其返回a的两倍。在main函数中,声明了一个B的对象,并调用了该对象中的geta()函数,将结果输出。这里也涉及到了多态性,因为通过指针p调用的是派生B中的geta()函数,而不是基A中的geta()函数。123 #### 引用[.reference_title] - *1* *2* *3* [C++实验8报告多态性虚函数](https://blog.youkuaiyun.com/qq_44621510/article/details/90724548)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值