实验6 多态性与虚函数
实验目的和要求
- <span style="font-family:SimSun;font-size:16px;">//sy6_1.cpp
- #include<iostream>
- using namespace std;
- class Base
- {
- public:
- virtual void f(float x){cout<<"Base::f(float)"<<x<<endl;}
- void g(float x){cout<<"Base::g(float)"<<x<<endl;}
- void h(float x){cout<<"Base::h(float)"<<x<<endl;}
- };
- class Derived:public Base
- {
- public:
- virtual void f(float x){cout<<"Derived::f(float}"<<x<<endl;}
- void g(int x){cout<<"Derived::g(int)"<<x<<endl;}
- void h(float x){cout<<"Derived::h(float)"<<x<<endl;}
- };
- int main()
- {
- Derived d;
- Base *pb=&d;
- Derived *pd=&d;
- pb->f(3.14f);
- pd->f(3.14f);
- pb->g(3.14f);
- pb->h(3.14f);
- pd->h(3.14f);
- return 0;
- }</span>
(1)找出以上程序中使用了重载和覆盖函数。
答:Base类中函数void g(); 和void h();与Derived类中的函数void g(); 和void h();函数名相同,参数类型不同,构成了函数重载。
- <span style="font-size:18px;">//sy6_3.cpp</span>
- <span style="font-size:18px;">#include<iostream></span>
- <span style="font-size:18px;">using namespace std;</span>
- <span style="font-size:18px;">class Base</span>
- <span style="font-size:18px;">{</span>
- <span style="font-size:18px;"> public:</span>
- <span style="font-size:18px;"> void f(int x){cout<<"Base::f(int)"<<x<<endl;}</span>
- <span style="font-size:18px;"> void f(float x){cout<<"Base::f(float)"<<x<<endl;}</span>
- <span style="font-size:18px;"> virtual void g(void){cout<<"Base::g(void)"<<endl;}</span>
- <span style="font-size:18px;">};</span>
- <span style="font-size:18px;">class Derived:public Base</span>
- <span style="font-size:18px;">{</span>
- <span style="font-size:18px;"> public:</span>
- <span style="font-size:18px;"> virtual void g(void){cout<<"Derived::g(void}"<<endl;}</span>
- <span style="font-size:18px;">};</span>
- <span style="font-size:18px;">int main()</span>
- <span style="font-size:18px;">{</span>
- <span style="font-size:18px;"> Derived d;</span>
- <span style="font-size:18px;"> Base *pb=&d;</span>
- <span style="font-size:18px;"> pb->f(42);</span>
- <span style="font-size:18px;"> pb->f(3.14f);</span>
- <span style="font-size:18px;"> pb->g();</span>
- <span style="font-size:18px;"> return 0;</span>
- <span style="font-size:18px;">}</span>
答:Base类中函数void f(); 在同一作用域中,函数名相同,参数类型不同,构成了函数重载。
输出结果解释: pb和pd指向同一地址,它们运行结果应该是相同的,但实际运行出来的结果却不相同,原因是决定pb和pd调用函数运行结果的不是他们指向的地址,而是他们的指针类型。“只有在通过基类指针或引用间接指向派生类子类型时多态性才会起作用”。在程序中pb是基类指针,pd是派生类指针,pd的所有函数调用都只是调用自己的函数,和多态性无关,所以pd的所有函数调用的结果都输出Derived::是完全正常的;pb的函数调用如果有virtual则根据多态性调用派生类的,如果没有virtual则是正常的静态函数调用,还是调用基类的,所以有virtual的f函数调用输出Derived::,其它两个没有virtual则还是输出Base::。
- <span style="font-size:16px;">//sy6_3.cpp</span>
- <span style="font-size:16px;">#include<iostream></span>
- <span style="font-size:16px;">using namespace std;</span>
- <span style="font-size:16px;">class Point</span>
- <span style="font-size:16px;">{</span>
- <span style="font-size:16px;"> public:</span>
- <span style="font-size:16px;"> Point(double i,double j){x=i;y=j;}</span>
- <span style="font-size:16px;"> double Area(){return 0.0;}</span>
- <span style="font-size:16px;"> private:</span>
- <span style="font-size:16px;"> double x,y;</span>
- <span style="font-size:16px;">};</span>
- <span style="font-size:16px;">class Rectangle:public Point</span>
- <span style="font-size:16px;">{</span>
- <span style="font-size:16px;"> public:</span>
- <span style="font-size:16px;"> Rectangle(double i,double j,double k,double l):Point(i,j){w=k;h=l;}</span>
- <span style="font-size:16px;"> double Area(){return w*h;}</span>
- <span style="font-size:16px;"> private:</span>
- <span style="font-size:16px;"> double w,h;</span>
- <span style="font-size:16px;">};</span>
- <span style="font-size:16px;">int main()</span>
- <span style="font-size:16px;">{</span>
- <span style="font-size:16px;"> Point p(3.5,7);</span>
- <span style="font-size:16px;"> double A=p.Area();</span>
- <span style="font-size:16px;"> cout<<"Area= "<<A<<endl;</span>
- <span style="font-size:16px;"> Rectangle r(1.2,3,5,7.8);</span>
- <span style="font-size:16px;"> A=r.Area();</span>
- <span style="font-size:16px;"> cout<<"Area= "<<A<<endl;</span>
- <span style="font-size:16px;"> return 0;</span>
- <span style="font-size:16px;">}</span>
写出程序的输出结果,并解释输出结果。
程序的输出结果如下:- <span style="font-size:16px;">//sy6_4.cpp</span>
- <span style="font-size:16px;">#include<iostream></span>
- <span style="font-size:16px;">using namespace std;</span>
- <span style="font-size:16px;">const double PI=3.1415;</span>
- <span style="font-size:16px;">class Shap</span>
- <span style="font-size:16px;">{</span>
- <span style="font-size:16px;"> public:</span>
- <span style="font-size:16px;"> virtual double Area()=0;</span>
- <span style="font-size:16px;">};</span>
- <span style="font-size:16px;">class Triangle:public Shap</span>
- <span style="font-size:16px;">{</span>
- <span style="font-size:16px;"> public:</span>
- <span style="font-size:16px;"> Triangle(double h,double w){H=h;W=w;}</span>
- <span style="font-size:16px;"> double Area(){return 0.5*H*W;}</span>
- <span style="font-size:16px;"> private:</span>
- <span style="font-size:16px;"> double H,W;</span>
- <span style="font-size:16px;">};</span>
- <span style="font-size:16px;">class Rectangle:public Shap</span>
- <span style="font-size:16px;">{</span>
- <span style="font-size:16px;"> public:</span>
- <span style="font-size:16px;"> Rectangle(double h,double w){H=h;W=w;}</span>
- <span style="font-size:16px;"> double Area(){return H*W;}</span>
- <span style="font-size:16px;"> private:</span>
- <span style="font-size:16px;"> double H,W;</span>
- <span style="font-size:16px;">};</span>
- <span style="font-size:16px;">class Circle:public Shap</span>
- <span style="font-size:16px;">{</span>
- <span style="font-size:16px;"> public:</span>
- <span style="font-size:16px;"> Circle(double r){R=r;}</span>
- <span style="font-size:16px;"> double Area(){return PI*R*R;}</span>
- <span style="font-size:16px;"> private:</span>
- <span style="font-size:16px;"> double R;</span>
- <span style="font-size:16px;">};</span>
- <span style="font-size:16px;">class Square:public Shap</span>
- <span style="font-size:16px;">{</span>
- <span style="font-size:16px;"> public:</span>
- <span style="font-size:16px;"> Square(double s){S=s;}</span>
- <span style="font-size:16px;"> double Area(){return S*S;}</span>
- <span style="font-size:16px;"> private:</span>
- <span style="font-size:16px;"> double S;</span>
- <span style="font-size:16px;">};</span>
- <span style="font-size:16px;">double Total(Shap *s[],int n)</span>
- <span style="font-size:16px;">{</span>
- <span style="font-size:16px;"> double sum=0;</span>
- <span style="font-size:16px;"> for(int i=0;i<n;i++)</span>
- <span style="font-size:16px;"> sum+=s[i]->Area();</span>
- <span style="font-size:16px;"> return sum;</span>
- <span style="font-size:16px;">}</span>
- <span style="font-size:16px;">int main()</span>
- <span style="font-size:16px;">{</span>
- <span style="font-size:16px;"> Shap *s[5];</span>
- <span style="font-size:16px;"> s[0]=new Square(8.0);</span>
- <span style="font-size:16px;"> s[1]=new Rectangle(3.0,8.0);</span>
- <span style="font-size:16px;"> s[2]=new Square(12.0);</span>
- <span style="font-size:16px;"> s[3]=new Circle(8.0);</span>
- <span style="font-size:16px;"> s[4]=new Triangle(5.0,4.0);</span>
- <span style="font-size:16px;"> double sum=Total(s,5);</span>
- <span style="font-size:16px;"> cout<<"SUM = "<<sum<<endl;</span>
- <span style="font-size:16px;"> return 0;</span>
- <span style="font-size:16px;">}</span>
- <span style="font-family:SimSun;font-size:16px;">//sy6_5.cpp
- #include <iostream>
- using namespace std;
- class Teacher
- {
- public:
- virtual int Salary()=0;
- virtual void Print(int)=0;
- };
- class Professor:public Teacher
- {
- private:
- char name[128];
- int lessons;
- public:
- Professor()
- {
- cout<<"请输入姓名:";
- cin>>name;
- cout<<"请输入课时:";
- cin>>lessons;
- };
- int Salary()
- {
- return (5000+lessons*50);
- };
- void Print(int money)
- {
- cout<<"职称:教授 姓名:"<<name<<" 薪水:"<<money<<endl<<endl;
- };
- };
- class AssociateProfessor:public Teacher
- {
- private:
- char name[128];
- int lessons;
- public:
- AssociateProfessor()
- {
- cout<<"请输入姓名:";
- cin>>name;
- cout<<"请输入课时:";
- cin>>lessons;
- };
- int Salary()
- {
- return (3000+lessons*30);
- };
- void Print(int money)
- {
- cout<<"职称:副教授 姓名:"<<name<<" 薪水:"<<money<<endl<<endl;
- };
- };
- class Lecturer:public Teacher
- {
- private:
- char name[128];
- int lessons;
- public:
- Lecturer()
- {
- cout<<"请输入姓名:";
- cin>>name;
- cout<<"请输入课时:";
- cin>>lessons;
- };
- int Salary()
- {
- return (2000+lessons*20);
- };
- void Print(int money)
- {
- cout<<"职称:讲师 姓名:"<<name<<"薪水:"<<money<<endl<<endl;
- };
- };
- int main()
- {
- Teacher *t = NULL;
- int money=0;
- t = new Professor();
- money = t->Salary();
- t->Print(money);
- delete t;
- t = new AssociateProfessor();
- money = t->Salary();
- t->Print(money);
- delete t;
- t = new Lecturer();
- money = t->Salary();
- t->Print(money);
- delete t;
- t = NULL;
- return 0;
- }</span>
答:重载与覆盖的区别:1、方法的覆盖是子类和父类之间的关系,是垂直关系;方法的重载是同一个类中方法之间的关系,是水平关系2、覆盖只能由一个方法,或只能由一对方法产生关系;方法的重载是多个方法之间的关系。3、覆盖要求参数列表相同;重载要求参数列表不同。4、覆盖关系中,调用那个方法体,是根据对象的类型(对象对应存储空间类型)来决定;重载关系,是根据调用时的实参表与形参表来选择方法体的。
答:静态联编是指联编工作在编译阶段完成的,这种联编过程是在程序运行之前完成的,又称为早期联编。要实现静态联编,在编译阶段就必须确定程序中的操作调用(如函数调用)与执行该操作代码间的关系,确定这种关系称为束定,在编译时的束定称为静态束定。静态联编对函数的选择是基于指向对象的指针或者引用的类型。其优点是效率高,但灵活性差。
动态联编是指联编在程序运行时动态地进行,根据当时的情况来确定调用哪个同名函数,实际上是在运行时虚函数的实现。这种联编又称为晚期联编,或动态束定。动态联编对成员函数的选择是基于对象的类型,针对不同的对象类型将做出不同的编译结果。C++中一般情况下的联编是静态联编,但是当涉及到多态性和虚函数时应该使用动态联编。动态联编的优点是灵活性强,但效率低。
动态联编的条件:
①必须把动态联编的行为定义为类的虚函数。
②类之间应满足子类型关系,通常表现为一个类从另一个类公有派生而来。
③必须先使用基类指针指向子类型的对象,然后直接或者间接使用基类指针调用虚函数。
实验总结
通过本次实验我了解静态联编的动态联编的概念以及静态联编和动态联编的区别,了解了什么是重载和覆盖函数掌握动态联编的条件。在同一个作用域内,函数名相同,参数列表不同(参数个数不同,或者参数类型不同,或者参数个数和参数类型都不同),返回值类型可相同也可不同,这种情况叫做C++的重载。而覆盖又被叫做重写,是当在子类中定义一个与父类完全相同的虚函数时,则称子类的这个函数重写了父类的这个虚函数。在之前一直都不明白这两者的概念含义,不知道怎么去运用,通过老师的讲解和实验的操作,大概了解了是怎么一回事,但是还需要在课下花时间去练习。