多态与虚函数 例题
c++多态性与虚函数习题
作业题一、写出下列程序运行结果1.#include<iostream>using namespace std;class A {public:virtual void func( ) {cout<<”func in class A”<<endl;} };class B{public:virtual void func( ) {cout<<”func in class B”<<endl;} };class C:public A,public B{public:void func( ) {cout<<”func in class C”<<endl:}};int main( ){C c;A& pa=c;B& pb=c;C& pc=c;pa.func( );pb.func( );pc.func( );}2.#include<iostream>using namespace std;class A{public:virtual ~A( ){cout<<”A::~A( ) called “<<endl; }};class B:public A{char *buf;public:B(int i) { buf=new char[i]; }virtual ~B( ){delete []buf;cout<<”B::~B( ) called”<<endl;}};void fun(A *a) {delete a;}int main( ){ A *a=new B(10);fun(a);}二、程序设计题1有一个交通工具类vehicle,将它作为基类派生小车类car、卡车类truck和轮船类boat,定义这些类并定义一个虚函数用来显示各类信息。
5.2定义一个shape抽象类,派生出Rectangle类和Circle类,计算各派生类对象的面积Area( )。
【C++面向对象的程序设计】6多态性
虚析构函数
析构函数的作用是对象撤销之后清理现场。 在派生类对象撤销时,一般先调用派生类的 析构函数。再调用基类的析构函数。
然而,当定义的是一个指向基类的指针变量, 使用new运算符建立临时对象时,如果基类 中有析构函数,则在使用delete析构时只会 调用基类的析构函数。
这就需要将基类中的析构函数声明为虚函数。
虚函数的声明与使用
声明虚函数的一般格式如下: virtual 函数原型;
⑴ 必须首先在基类中声明虚函数。 ⑵ 派生类中与基类虚函数原型完全相同的成员函 数,即使在说明时前面没有冠以关键字virtual也 自动成为虚函数。
声明虚函数
⑶ 只有非静态成员函数可以声明为虚函数。 ⑷ 不允许在派生类中定义与基类虚函数名字及参数 特征都相同,仅仅返回类型不同的成员函数。 编译时 出错。 ⑸ 系统把函数名相同但参数特征不同的函数视为不 同的函数。 ⑹ 通过声明虚函数来使用C++提供的多态性机制时, 派生类应该从它的基类公有派生。
构函数等内容。
本章内容
静态联编与动态联编 虚函数的声明与使用 纯虚函数和抽象类 虚析构函数
Hale Waihona Puke 静态联编与动态联编所谓联编(tinding),就是使一个计算机程序的不同部 分彼此关联的过程。
静态联编在编译阶段完成,因为所有联编过程都在程 序开始运行之前完成,因此静态联编也叫先前联编或早期 联编。
另一种情况编译程序在编译时并不确切知道应把发送 到对象的消息和实现消息的哪段具体代码联编在一起,而 是在运行时才能把函数调用与函数体联系在一起,则称为 动态联编。
动态联编的实现
C ++语言中的动态联编是通过使用虚函数表 (Virtual Function Table)来实现的,虚函数表也称 为v-表。
C++(练习)第9章,多态性与虚函数
B虚函数
C派生类
D其他都不对
参考答案
A
5.关于虚函数的描述中,()是正确的。
A虚函数是一个静态成员函数
B虚函数是一个非成员函数
C虚函数既可以在函数说明时定义,也可以在函数实现时定义
D派生类的虚函数与基类中对应的虚函数具有相同的参数个数和类型
参考答案
D
6.下面4个选项中,()是用来声明虚函数的。
C virtual void tt(int);
D virtual void tt(int){ };
参考答案
A
二.填空题
1.如果类包含了一个或多个__1__,则它是抽象类。
参考答案
1:纯虚函数
2.虚函数必须是类的__1__。
参考答案
1:非静态成员函数或成员函数
3.多态性分为两类:编译时的多态性和__1__的多态性。
参考答案
1:友元函数
7.如果在类中定义了一个成员函数为__1__,则表明在该继承层次链条的派生类中有可能重新定义这个成员函数的实现,即它可能被派生类的同名函数所覆盖。
参考答案
1:虚函数
8.动态多态性通过__1__实现。
参考答案
1:虚函数
9.定义一个函数名为fun,返回值为int,没有参数的纯虚函数的定义是__1__。
参考答案
1:引用或指针
20.含有纯虚函数的类称为__1__。
参考答案
1:抽象类
21.在C++中,编译时的多态性是通过函数重载和__1__体现的。
参考答案
1:模板
三.问答题
四.编程题
参考答案
1:纯虚函数
12.虚函数必须是类的__1__。
《Java程序设计案例教程》第十章练习答案
第10章多态性与虚函数一、单项选择题1.实现运行时的多态性要使用(D)。
A.重载函数B.构造函数C.析构函数D.虚函数2.通过运算符重载,可以改变运算符原有的(A)。
A.操作数类型B.操作数个数C.优先级D.结合性3.将运算符重载为类成员函数时,其参数表中没有参数,说明该运算符是(B)。
A.不合法的运算符B.一元运算符C.无操作数的运算符D.二元运算符4.在重载一个运算符时,其参数表中没有任何参数,说明该运算符是(B)。
A.作为友元函数重载的一元运算符B.作为成员函数重载的一元运算符C.作为友元函数重载的二元运算符D.作为成员函数重载的二元运算符5.如果表达式++a中的"++"是作为成员函数重载的运算符,若采用运算符函数调用格式,则可表示为(D)。
A.a.operator++(1)B.operator++(a)C.operator++(a,1)D.a.operator++()6.如果表达式a>=b中的">="是作为非成员函数重载的运算符,则可以等效地表示为(C)。
A.a.operator>=(b)B.b.operator>=(a)C.operator>=(a,b)D.perator>=(b,a)7.有如下程序:#include<iostream>using namespace std;class A{public:virtual void funl (){cout<<"A1";}void fun2 (){cout<<"A2";}};class B: public A{public:void funl (){cout<<"Bl";}void fun2 (){cout<<"B2";}};int main(){A*p=new B;p->funl ();p->fun2();return 0;}程序执行后,输出结果为(C)。
实验三 虚函数与多态 纯虚函数(完整版)
实验三虚函数与多态、纯虚函数一.实验目的1. 在掌握继承与派生关系的基础上,进一步理解虚函数与多态性的关系,实现运行时的多态。
2. 学会定义和使用纯虚函数二、实验容1.例:了解"单接口,多方法"的概念。
现有称为figure的基类,存放了各二维对象(三角形、矩形和圆形三个类)的各维数据,set_dim()设置数据,是标准成员函数。
show_area()为虚函数,因为计算各对象的面积的方法是不同的。
【程序】#include < iostream >using namespace std;class figure{protected:double x,y;public:void set_dim(double i,double j=0){ x=i; y=j; }virtual void show_area(){ cout<<"No area computation defined for this class.\n";}};class triangle:public figure{void show_area(){ cout<<"Triangle with height "<< x<<" and base "<< y<<" has an area of "<< x*0.5*y<< endl;}};class square:public figure{public:void show_area(){ cout<<"Square with dimensions "<< x<<" and "<< y<<" has an area of "<< x*y<< endl;}};class circle:public figure{public:void show_area(){ cout<<"Circle with radius "<< x<<" has an area of "<<3.14159*x*x<< endl;}};int main(){figure *p;triangle t;square s;circle c;p->set_dim(10.0,5.0);p->show_area();p=&s;p->set_dim(10.0,5.0);p->show_area();p=&c; p->set_dim(10.0);p->show_area();return 0;}【要求】(1)建立工程,录入上述程序,调试运行并记录运行结果。
实验七 虚函数及应用
实验七虚函数及应用一、实验目的1.理解虚函数与运行时(动态)多态性之间的关系,掌握虚函数的定义及应用;2.理解纯虚函数与抽象类的概念,掌握抽象类的定义及应用;3.理解虚析构函数的概念及作用。
二、实验学时课内实验:2课时课外练习:2课时三本实验涉及的新知识㈠虚函数与动态多态性在C++中,如果将基类与派生类的同名成员函数定义为虚函数,就可以定义一个基类指针,当基类指针指向基类对象时访问基类的成员函数,当基类指针指向派生类对象时访问派生类的成员函数,实现在运行时根据基类指针所指向的对象动态调用成员函数,实现动态多态性。
换句话说,虚函数与派生类相结合,使C++能支持运行时(动态)多态性,实现在基类中定义派生类所拥有的通用“接口”,而在派生类中定义具体的实现方法,即“一个接口,多种方法”。
㈡虚函数的定义1.在基类中定义在定义函数的前面加上“virtual ”。
即:virtual 返回类型函数名(参数表){ …… }2.在派生类中定义函数的返回类型、函数名、参数的个数、参数类型及顺序必须与基类中的原型完全相同。
3.说明:⑴在派生类中定义虚函数时,可用“virtual”也可不用“virtual”(最好都使用)。
⑵虚函数在派生类中重新定义时,其原型必须与基类中相同。
⑶必须用基类指针访问虚函数才能实现运行时(动态)多态性;当用普通成员函数的调用方法(即用圆点运算符)调用虚函数时,为静态调用;⑷虚函数在自身类中必须声明为成员函数(不能为友元函数或静态成员函数),但在另一个类中可以声明为友元函数。
⑸虚函数可以公有继承多次,其虚函数的特性不变。
⑹构造函数不能定义为虚函数,但析构函数可以定义为虚函数。
⑺虚函数与重载函数的关系①普通函数重载是通过参数类型或参数的个数不同实现的;重载一个虚函数时,其函数原型(返回类型、参数个数、类型及顺序)完全相同。
②当重载的虚函数只有返回类型不同时,系统将给出错误信息;如果定义的虚函数只有函数名相同,而参数个数或类型不同时,则为普通函数重载。
C++多态练习题
C++多态练习题⼀、填空题(1)C++的两种联编⽅式为:动态联编和静态联编。
(2)C++⽀持两种多态性,静态联编所⽀持的多态性被称为编译时的多态性、动态联编所⽀持的多态性被称为运⾏时的多态性。
(3)重载函数在编译时表现出多态性,是静态联编;⽽虚函数则在运⾏时表现出多态性是动态联编。
(4)为了区分重载函数,把⼀个派⽣类中重定义基类的虚函数称为覆盖。
(5)如果派⽣类与基类的虚函数仅仅返回类型不同,其余相同,则c++认为是使⽤了不恰当的虚函数。
(6)在构造函数和析构函数中调⽤虚函数时,采⽤静态联编。
(7)纯函数的定义是在虚函数定义的基础上,再让函数等于0 。
(8)对于包含有纯虚函数的类被称为抽象类。
⼆、选择题(⾄少选⼀个,可以多选)(1)⽤关键字(A)标记的函数被称为虚函数。
A.virtualB.privateC.publicD.protected(2)在C++中,要实现动态联编,必须使⽤(D)调⽤虚函数。
A.类名B.派⽣类指针C.对象名D.基类指针(3)下列函数中,可以作为虚函数的是(BD)。
A.普通函数B.⾮静态成员函数C.构造函数D.析构函数(4)在派⽣类中,重载⼀个虚函数时,要求函数名、参数的个数、参数的类型、参数的顺序和函数的返回值(B)。
A.不同B.相同C.相容D.部分相同(5)使⽤虚函数保证了在通过⼀个基类类型的指针(含引⽤)调⽤⼀个虚函数时,c++系统对该调⽤进⾏(A),但是,在通过⼀个对象访问⼀个虚函数,使⽤(B)。
A.动态联编B.静态联编C.动态编译D.静态编译(6)下⾯函数原型声明中,(C)声明的fun()为纯虚函数。
A.void func()=0;B.virtual void func()=0;B.virtual void func();C.virtual void func(){};(7)若⼀个类中含有纯虚函数,则该类称为(C)。
A.基类B.虚基类C.抽象类D.派⽣类(8)假设Myclass为抽象类,下列声明(CD)是错误的。
虚 函 数
(6)一个虚函数无论被公有继承多少次,它仍然保持其 虚函数的特性。
my_base--------
10 20
从程序运行的结果可以看出,虽然执行语句mp=&mc;后, 指针mp已经指向了对象mc,但是它所调用的函数(mp>show()),仍然是其基类对象的show(),显然这不是我 们所期望的。出现这个问题的原因以及解决方法,我 们将在下一节介绍。在此先说明引入派生类后,使用 对象指针应注意的几个问题:
derive op2; //定义派生类derive的对象op2
ptr=&op1;
//使指针ptr指向对象op1
ptr=&op2;
//错误,不允许将base类指针ptr指
向它的私有派生类//对象op2
//…
}
(2)允许将一个声明为指向基类的指针指向公有派生类
的对象,但是不能将一个声明为指向派生类对象的指 针指向其基类的对象。
(3)声明为指向基类的指针,当其指向公有派生的
对象时,只能用它来直接访问派生类中从基类继承来
的成员,而不能直接访问公有派生类中定义的成员,
例如:
class A { //... public: void print1(); }; class B:public A{ //... public: print2(); };
可见,虚函数同派生类的结合和使C++支持运行时的多 态性,而多态性对面向对象的程序设计是非常重要的, 实现了在基类定义派生类所拥有的通用接口,而在派 生类定义具体的实现方法,即常说的“同一接口,多 种方法”。
5-4虚函数与多态.docx
虚函数与多态多态是面向对象程序设计的三大重要特征之一。
作为C++中的术语,多态是指使用相同的函数名来访问函数不同实现的方法。
正因为如此,多态也可以被描述为“一种接口,多种方法”。
也就是说可以使用相同的形式来访问一组通用的运算,即使与每个运算对应的具体行为可能不同。
C++支持编译时多态和运行时多态。
运算符重载和函数重载就是编译时多态的一种表现。
虽然运算符重载和函数重载的功能很强大,但它们不能满足一个完整的面向对象语言的全部需求。
因此,在C++中除了实现编译时多态之外, 还使用派生类和虚函数来实现运行时多态,这也是本章的主题。
本章首先将简短地讨论指向派生类型的指针,因为它们提供了对运行时多态的支持。
541指向派生类型的指针运行时多态的基础是基类型指针。
基类型指针和派生类型指针可以通过多种方法进行关联,而其他类型的指针则不能。
在前面讲到,某个类型的指针一般不能指向其他类型的对象,但基类型指针和派生类型指针除外。
在C++中,基类型指针可以指向任何派生类型的对象。
例如,假设有一个基类B_ class和一个B_ class的派生类D_ classo在C++中,所有被声明为指向B_ class类型的指针同时也可以指向D_ class类型。
因此,假设:B_ class *p; //B_ class 类型的指针B_ class B_ ob; //B_ class 类型的对象D_ class D_ob; //D_ class 类型的对象那么下面两条语句是完全合法的:p二&B_ ob; //p指向B_ class类型的对象p二&D_ ob; /*p指向D_ class类型的对象,这个类派生于B_ class*/ 在上面的代码中,p可以用来访问D_ob中所有从B_ob继承的成员,但不能访问D_ob中定义的成员。
下面我们再来看一个更具体的示例,下面的程序定义了一个基类B_ class 和一个派生类D_ class,程序中使用了简单的类层次结构来保存作者姓名和书名。
多态与虚函数bk
试验四:多态与虚函数实验说明:1.请大家按照要求上机练习调试。
把按照题目要求调试好的代码写在实验报告上。
2.同时请思考,并在实验报告上写下问题及答案1)在使用#include命令时,用双撇号还是尖括号把文件名括起来?为什么?2)在主函数中需要把所有的头文件和函数文件都包含进来吗?只需要包含哪些头文件,为什么?3)为什么常常把类的定义和成员函数的定义分开放在两个文件中,而不是放在同一个文件里?4)根据什么考虑把一个成员函数声明为一个虚函数?1、试验目的:(1)了解多态性的概念(2)了解虚函数的作用及使用方法(3)了解纯虚函数和抽象类的概念和用法2、试验内容:上机调试程序和运行程序,分析结果。
在例题6-1程序上作一些修改,在程序中使用虚函数和抽象类。
声明一个抽象基类shap (形状),派生出Point(点)类,由Point类派生出Circle(圆)类,再由Circle类派生出Cylinder(圆柱体)类。
将类的声明部分分别作为4个头文件,对点、圆、圆柱体的成员函数的定义部分分别作为3个源文件(.cpp文件),形状类的成员函数定义可放在头文件中,在主函数中用#include命令把他们包含进来,形成一个完整的程序,并上机运行。
例题6-1#include <iostream.h>//声明抽象基类Shapeclass Shape{public:virtual float area() const {return 0.0;} //虚函数virtual float volume() const {return 0.0;} //虚函数virtual void shapeName() const =0; //纯虚函数};//声明Point类class Point:public Shape //Point是Shape的公用派生类{public:Point(float=0,float=0);void setPoint(float,float);float getX() const {return x;}float getY() const {return y;}virtual void shapeName() const {cout<<"Point:";} //对纯虚函数进行定义friend ostream & operator<<(ostream &,const Point &);protected:float x,y;//定义point类的成员函数Point::Point(float a,float b){x=a;y=b;}void Point::setPoint(float a,float b){x=a;y=b;}ostream & operator<<(ostream &output,const Point &p){output<<"["<<p.x<<","<<p.y<<"]";return output;}//声明Point类的派生类Circle类class Circle:public Point{public:Circle(float x=0,float y=0,float r=0);void setRadius(float);float getRadius() const;virtual float area() const;virtual void shapeName() const {cout<<"Circle:";} //对纯虚函数进行再定义friend ostream &operator<<(ostream &,const Circle &);protected:float radius;};//定义Circle的成员函数Circle::Circle(float a,float b,float r):Point(a,b),radius(r){}void Circle::setRadius(float r){radius=r;}float Circle::getRadius() const {return radius;}float Circle::area() const{return 3.14159*radius*radius;}ostream &operator<<(ostream &output,const Circle &c){output<<"["<<c.x<<","<<c.y<<"], r="<<c.radius;return output;//声明Circle的派生类Cylinderclass Cylinder:public Circle{public:Cylinder (float x=0,float y=0,float r=0,float h=0);void setHeight(float);float getHeight() const;virtual float area() const;virtual float volume() const;virtual void shapeName() const {cout<<"Cylinder:";} //对纯虚函数进行再定义friend ostream& operator<<(ostream&,const Cylinder&);protected:float height;};//定义Cylinder的成员函数Cylinder::Cylinder(float a,float b,float r,float h):Circle(a,b,r),height(h){}void Cylinder::setHeight(float h){height=h;}float Cylinder::getHeight() const {return height;}float Cylinder::area() const{ return 2*Circle::area()+2*3.14159*radius*height;}float Cylinder::volume() const{return Circle::area()*height;}ostream &operator<<(ostream &output,const Cylinder& cy){output<<"["<<cy.x<<","<<cy.y<<"], r="<<cy.radius<<", h="<<cy.height;return output;}//主函数int main(){Point point(3.2,4.5); //建立Point类对象pointCircle circle(2.4,12,5.6); //建立Circle类对象circleCylinder cylinder(3.5,6.4,5.2,10.5); //建立Cylinder类对象cylinderpoint.shapeName(); //静态关联cout<<point<<endl;circle.shapeName(); //静态关联cout<<circle<<endl;cylinder.shapeName(); //静态关联cout<<cylinder<<endl<<endl;Shape *pt; //定义基类指针pt=&point; //指针指向Point类对象pt->shapeName(); //动态关联cout<<"x="<<point.getX()<<",y="<<point.getY()<<"\narea="<<pt->area() <<"\nvolume="<<pt->volume()<<"\n\n";pt=&circle; //指针指向Circle类对象pt->shapeName(); //动态关联cout<<"x="<<circle.getX()<<",y="<<circle.getY()<<"\narea="<<pt->area() <<"\nvolume="<<pt->volume()<<"\n\n";pt=&cylinder; //指针指向Cylinder类对象pt->shapeName(); //动态关联cout<<"x="<<cylinder.getX()<<",y="<<cylinder.getY()<<"\narea="<<pt->area() <<"\nvolume="<<pt->volume()<<"\n\n";return 0;}。
C++继承,虚函数与多态性专题
本文作者:黄邦勇帅学习本文首先你应熟悉C++中的构造函数,基本的类的声明及怎样初始化类,关于这些问题,请参看本人所作的《C++构造函数,复制构造函数和析构函数》一文,在这篇文章中作了详细的介绍。
本文分两部分即继承和虚函数与多态性,本文第一部分详细讲解了继承时的构造函数和析构函数的问题,父类与子类的同名变量和函数问题,最后介绍了多重继承与虚基类。
本文第二部分重点介绍了虚函数与多态性的问题,因此学习虚函数的基础是继承,因此在学习虚函数前应学好继承。
本文详细易懂,内容全面,是学习C++的不错的资料。
本文内容完全属于个人见解与参考文现的作者无关,其中难免有误解之处,望指出更正。
声明:禁止抄袭本文,若需要转载本文请注明转载的网址,或者注明转载自“黄邦勇帅”。
主要参考文献:1、C++.Primer.Plus.第五版.中文版[美]Stephen Prata著孙建春韦强译人民邮电出版社2005年5月2、C++.Primer.Plus.第四版.中文版Stanley B.Lippman、Barbara E.Moo著李师贤等译人民邮电出版社2006年3月3、C++.Primer.Plus.第三版.中文版Stanley B.Lippman等著潘爱民张丽译中国电力出版社2002年5月4、C++入门经典第三版[美]Ivor Horton著李予敏译清华大学出版社2006年1月5、C++参考大全第四版[美]Herbert Schidt著周志荣朱德芳于秀山等译电子工业出版社2003年9月6、21天学通第四版C++ [美]Jesse Liberty著康博创作室译人民邮电出版社2002年3月14 继承(基类,父类,超类),派生类,子类一:继承中的访问权限关系。
1.基类,父类,超类是指被继承的类,派生类,子类是指继承于基类的类.2.在C++中使用:冒号表示继承,如class A:public B;表示派生类A从基类B继承而来3.派生类包含基类的所有成员,而且还包括自已特有的成员,派生类和派生类对象访问基类中的成员就像访问自已的成员一样,可以直接使用,不需加任何操作符,但派生类仍然无法访问基类中的私有成员.4.在C++中派生类可以同时从多个基类继承,Java不充许这种多重继承,当继承多个基类时,使用逗号将基类隔开.5.基类访问控制符,class A:public B基类以公有方式被继承,A:private B基类以私有方式被继承,A:protected B基类以受保护方式被继承,如果没有访问控制符则默认为私有继承。
c多态性与虚函数习题
1.1C++支持两种多态性,分别是静态和动态。
1.2在编译时就确定的函数调用称为静态联编,它通过使用重载函数实现。
1.3在运行时才确定的函数调用称为动态联编,它通过虚函数来实现。
1.4虚函数的声明方法是在函数原型前加上关键字virtual。在基类中含有虚函数,在派生类中的函数没有显式写出virtual关键字,系统依据以下规则判断派生类的这个函数是否是虚函数:该函数是否和基类的虚函数参数个数相同 /同名;是否与基类的虚函数相应类型相同;是否与基类的虚函数返回值类型相同。如果满足上述3个条件,派生类的函数就是虚函数。并且该函数覆盖基类的虚函数。
A.可以说明虚函数
B.可以进行构造函数重载
C.可以定义友元函数
D.不能定义其对象
3.8类B是类A的公有派生类,类A和类B中都定义了虚函数func( ),p是一个指向类A对象的指针,则p->A::func( )将()。
A.调用类A中的函数func( )
B.调用类B中的函数func( )
C.根据p所指的对象类型而确定调用类A中或类B中的函数func( )
using namespace std;
class A {
public:
virtual void func( ) {cout<<”func in class A”<<endl;}
};
class B{
public:
virtual void func( ) {cout<<”func in class B”<<endl;}
A.虚析构函数B.虚构造函数
C.纯虚函数D.静态成员函数
3.6以下基类中的成员函数,哪个表示纯虚函数(C)。
C++程序设计基础第6章 虚函数与多态性
6.2.1 虚函数的定义
2. 虚函数的定义 • 虚函数的定义是在基类中进行的 。 • 虚函数的定义语法格式如下:
virtual<函数类型><函数名>(形参表) {
函数体 }
12
6.2.1 虚函数的定义
3. 定义虚函数时,要注意遵循以下规则: 1)只有成员函数才能声明为虚函数,因为虚
函数仅适用于有继承关系的类对象,所以 普通函数不能声明为虚函数。 2)虚函数的声明只能出现在类声明中的函数 原型声明中,而不能出现在成员的函数体 实现上。 3)类的静态成员函数不可以定义为虚函数, 因为静态成员函数不受限于某个对象。
}
7
void main()
{
MaxClass mc(34,67,143,89);
cout<<"计算前两个数中的最大数为:“
<<mc.max(34,67)<<endl;
cout<<"计算前三个数中的最大数为:“
<<mc.max(34,67,143)<<endl;
cout<<"计算四个数中的最大数为:“
运行结果: 张晓强,园林工人 李文卓,生命科学教师
23
6.2.3 虚函数的重载
• 2. 多继承中的虚函数
【例6.8】多继承中使用虚函数例题。
#include <iostream.h>
class base1
//定义基类base1
{
public: virtual void display()
//函数定义为虚函数
运行结果:
(1) : 动物(食草/食肉). (2) : 食草动物 : 羚羊 (3) : 食草动物 : 羚羊 (4) : 食肉动物 : 老虎 (5) : 食肉动物 : 老虎 (6) : 食草动物 : 羚羊 (7) : 食肉动物 : 老虎
第9章虚函数和多态
第9章虚函数和多态《第9章虚函数和多态》课后作业1、设计一个抽象基类Worker,并从该基类中派生出计时工人类HourlyWorker 和计薪工人类SalariedWorker。
每名工人都具有姓名name、年龄age、性别sex 和小时工资额pay_per_hour等属性;周薪计算成员函数voidCompute_pay(double hours),(其中参数hours 为每周的实际工作时数)和用于显示工人的基本信息的标准输出运算符友元函数ostream&operator<<(ostream&out, Worker&worker)。
工人的薪金等级以小时工资额划分:计时工人的薪金等级分为10、20 和40 US$/hour 三个等级;计薪工人的薪金等级,分为30 和50 US$/hour 两个等级。
不同类别和等级工人的周薪计算方法不同,计时工人周薪的计算方法是:如果每周的工作时数(hours)在40 以内,则周薪= 小时工资额×实际工作时数;如果每周的工作时数(hours)超过40,则周薪= 小时工资额×40 + 1.5 ×小时工资额×(实际工作时数–40)。
而计薪工周薪的计算方法是:如果每周的实际工作时数不少于35 小时,则按40 小时计周薪(允许有半个工作日的事/病假),超出40 小时部分不计薪,即周薪= 小时工资额×40;如果每周的实际工作时数少于35 小时(不含35 小时),则周薪= 小时工资额实际工作时数+ 0.5 ×小时工资额×(35 - 实际工作时数)。
要求:1. 定义Worker、HourlyWorker和SalariedWorker类,并实现它们的不同周薪计算方法。
2. 在主函数main()中使用HourlyWorker和SalariedWorker类完成如下操作:①通过控制台输入、输出操作顺序完成对5 个不同工人的基本信息(姓名、年龄、性别、类别和薪金等级)的注册。
(笔试题)关于C++的虚函数和多态性
(笔试题)关于C++的虚函数和多态性以下两段程序的输出是什么?程序1:#include "stdio.h"class Base{public:int Bar(char x){return (int)(x);}virtual int Bar(int x){return (2 * x);}};class Derived : public Base{public:int Bar(char x){return (int)(-x);}int Bar(int x){return (x / 2);}};int main(void){Derived Obj;Base *pObj = &Obj;printf("%d,", pObj->Bar((char)(100)));printf("%d,", pObj->Bar(100));}分析:答案:100 50Derived Obj;Base *pObj = &Obj;printf("%d,", pObj->Bar((char)(100)))printf("%d,", pObj->Bar(100));第⼀个Bar(char)是⾮虚函数,因此是静态绑定,静态绑定是指指针指向声明时的对象,pObj声明时为Base类,因此调⽤的是Base类的Bar(char)第⼆个Bar(char)是虚函数,因此是动态绑定,动态绑定是指指针指向引⽤的对象,pObj引⽤Derived对象,因此调⽤的是Derived类的Bar(int)程序2:#include <iostream>using namespace std;class animal{protected:int age;public:virtual void print_age(void) = 0;};class dog : public animal{public:dog(){ this->age = 2; }~dog(){}virtual void print_age(void){ cout << "wang. my age=" << this->age << endl; }};class cat:public animal{public :cat(){ this->age = 1; }~cat(){}virtual void print_age(void){ cout << " Miao,my age= " << this->age << endl; }};int main(void){cat kitty;dog jd;animal *pa;int *p = (int *)(&kitty);int *q = (int *)(&jd);//cout << p[1] << endl;//cout << q[1] << endl;p[1] = q[1];pa = &kitty;pa->print_age();return 0;}分析:答案:Miao, my age =2int*p = (int*)(&kitty);int*q = (int*)(&jd);p和q是分别指向kitty和jd两个对象的⾸地址,因为类Cat和Dog都包含虚函数,所以kitty和jd两个对象均包含⼀个虚函数表,并通过⼀个指针指向它,p[0]和q[0]就是该虚函数表指针,⽽p[1]和q[1]则为该对象的数据成员即age的值,p[1]=1,q[1]=2p[1] = q[1]=2;kitty的age被修改为2,animal *pa;pa = &kitty;pa->print_age();pa指针声明时的类型为基类animal,它指向派⽣类kitty对象,典型的多态特性,则pa的静态类型为animal,动态类型为cat。
多态与虚函数 练习题
多态与虚函数练习选择题单选题1.要实现动态多态性,可以通过()调用虚函数。
A. 基类指针B. 成员名限定C. 对象名D. 派生类名2.以下()成员函数表示纯虚函数。
A. virtual int vf(int);B. void vf(int)=0;C. virtual void vf()=0;D. virtual void vf(int) { };3.关于纯虚函数和抽象类的描述中,错误的是()。
A. 纯虚函数是一种特殊的虚函数,它没有具体的实现B. 抽象类是指具有纯虚函数的类C. 一个基类中说明有纯虚函数,该基类派生类一定不再是抽象类D. 抽象类只能作为基类来使用,其纯虚函数的实现由派生类给出4.下面4个选项中,()是用来声明虚函数的。
A. virtualB. publicC. usingD. false5.下列关于动态联编的描述中,错误的是()。
A. 动态联编是以虚函数为基础B. 动态联编是运行时确定所调用的函数代码的C. 动态联编调用函数操作是指向对象的指针或对象引用D. 动态联编是在编译时确定操作函数的6.关于虚函数的描述中,()是正确的。
A. 虚函数是一个静态成员函数B. 虚函数是一个非成员函数C. 虚函数既可以在函数说明时定义,也可以在函数实现时定义D. 派生类的虚函数与基类中对应的虚函数具有相同的参数个数和类型7.下面关于友元的描述中,错误的是()。
A. 友元函数可以访问该类的私有数据成员B. 一个类的友元类中的成员函数都是这个类的友元函数C. 友元可以提高程序的运行效率D. 类与类之间的友元关系可以继承8.下面描述中,正确的是()。
A. virtual可以用来声明虚函数B. 含有纯虚函数的类是不可以用来创建对象的,因为它是虚基类C. 即使基类的构造函数没有参数,派生类也必须建立构造函数D. 静态数据成员可以通过成员初始化列表来初始化9.如果一个类至少有一个纯虚函数,那么就称该类为()A. 抽象类B. 虚函数C. 派生类D. 以上都不对10.下列描述中,()是抽象类的特征。
多态性例题
多态性1 知识要点1.多态性:多态是指同样的消息被不同类型的对象接收后导致完全不同的行为。
2.面向对象的多态性可以分为4类:重载多态、强制多态、包含多态和参数多态。
3.多态从实现的角度来讲可以划分为两类:编译时的多态和运行时的多态。
4.运算符重载是对已有的运算符赋予多重含义,使同一个运算符作用于不同类型的数据导致不同类型的行为。
5.运算符重载的规则如下:1)C++语言中的运算符除了少数几个之外,全部可以重载,而且只能重载C++语言中已有的运算符。
2)重载之后运算符的优先级和结合性都不会改变。
3)运算符重载是针对新类型数据的实际需要,对原有运算符进行适当的改造。
一般来讲,重载的功能应当与原有功能相类似,不能改变原运算符的操作对象个数,同时至少要有一个操作对象是自定义类型。
不能重载的运算符只有5个,它们是类属关系运算符“.”、成员指针运算符“*”、作用域分辨符“::”、sizeof运算符和三目运算符“?:”。
前面两个运算符保证了C++语言中访问成员功能的含义不被改变。
作用域分辨符和sizeof运算符的操作数是类型,而不是普通的表达式,也不具备重载的特征。
6.运算符的重载形式有两种,重载为类的成员函数和重载为类的友元函数。
运算符重载为类的成员函数的一般语法形式为:函数类型 operater 运算符(形参表){ 函数体;}运算符重载为类的友元函数的一般语法形式为:friend 函数类型 operater 运算符(形参表){ 函数体;}7.虚函数说明虚函数的一般格式如下:virtual <函数返回类型说明符> <函数名>(<参数表>)在定义虚函数时要注意:(1) 虚函数是非静态的、非内联的成员函数,而不能是友元函数,但虚函数可以在另一个类中被声明为友元函数。
(2) 虚函数声明只能出现在类定义的函数原型声明中,而不能在成员函数的函数体实现的时候声明。
(3) 一个虚函数无论被公有继承多少次,它仍然保持其虚函数的特性。
虚函数部分习题
Class Mammal
{
Public:
(1)void Speak(){cout<<”This is a Mammal!”<<endl;}
};
Class Dog:public Mammal
{
Public:
void Speak(){cout<<”this is a Dog!”<<endl;}
{
B b,*pb=&b;
A a,*pa=&a;
void (A::*paf1)()=A::f1;
void (A::*paf2)()=A::f2;
void (B::*pbf1)()=B::f1;
void (B::*pbf2)()=B::f2;
(pa->*paf1)();
pa=&b;
(pa->*paf1)();
pa->print(); pb->print();
delete pa;
}
5.下列程序中声明一个Mammal类,再由此派生出Dog类,二者都定义Speak()成员函数,基类中定义Speak()为虚函数。主程序中分别声明一个Mammal类和Dog类的对象,再分别 用对象名.函数名和指针的形式调用Speak()函数。请填空完成程序,并上机运行验证。
{
protected:
int k;
public:
XX ( int n = 5 ) : k (n){ }
~XX ( )
{cout<<“XX”;}
virtual void f ( ) ;
};
void XX :: f ( )
第12章 多态性与虚函数补充习题
第十二章多态性与虚函数一、选择题1、下面哪个不能实现多态(C )。
A)函数重载 B)虚函数 C)虚基类 D)运算符重载2、下面有关抽象类的说法不正确的是( A )。
A)抽象类是可以定义对象的B)抽象类通常作为基类使用C)抽象类处于继承层次结构的较上层D)抽象类刻画了一组子类操作的通用接口3、下面有关纯虚函数的说法错误的是( D )。
A)派生类可以不重新定义纯虚函数B)运算符重载函数可以被定义为纯虚函数C)纯虚函数可以被重载D)基类中的纯虚函数在派生类的对象中无法访问4、关于虚函数,正确的描述是(A )。
A)构造函数不能是虚函数B)析构函数不能是虚函数C)虚函数可以是友元函数D)虚函数是静态成员函数5、如果在基类中将show()函数声明为不带返回值的纯虚函数,正确的写法是( C )。
A)virtual show()=0;B)virtual void show();C)virtual void show()=0;D)void show()=0 virtual;6、关于动态联编的描述中,( D )是错误的。
A) 动态联编是以虚函数为基础的B) 动态联编是在运行时,确定所调用的函数代码的。
C) 动态联编调用函数操作是通过指向对象的指针或对象的引用实现的。
D) 动态联编是在编译时确定操作函数的。
7、下列关于抽象类的使用中,( A )是错误的。
A) 可以定义抽象类的对象 B) 可以定义抽象类的指针C) 可以定义抽象类的引用 D) 可以定义抽象类的派生类8、关于虚函数的描述中,(C )是正确的。
A) 虚函数是一个非static类的成员函数。
B) 虚函数是一个非成员函数。
C) 基类中说明了虚函数后,派生类中与其对应的函数可以不必说明为虚函数。
D) 派生类的虚函数与基类的虚函数具有不同的参数个数和类型。
9、关于纯虚函数和抽象类的描述中,( C )是错误的。
A) 纯虚函数是一种特殊的虚函数,它没有具体的实现。
B) 抽象类是指含有纯虚函数的类。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
题目:水果类与虚函数多态与虚函数例题
1.题目内容与要求
①首先设计一个水果类(Fruit)作为基类,成员函
数为显示“水果”函数;
②然后设计Fruit类的四个派生类:香蕉类
(Banana)、苹果类(Apple)、梨子类(Pear)和桃子类(Peach),成员函数分别为显示“香
蕉”、“苹果”、“梨子”和“桃子”函数;
③最后在主函数中定义这些类的对象,并调用它们
的显示函数。
2.类的分析
主函数
水果类对象 香蕉类对象 苹果类对象 梨子类对象 桃子类对象 显示函数调用
水果类
显示函数
香蕉类
显示函数
苹果类
显示函数
梨子类
显示函数
桃子类
显示函数
3.类的设计
main
Fruit f; Banana b; Apple a; Pear p; Peach ph; f=b; f.print(); f=a; f.print(); ……
Fruit
print
Banana
print
Apple
print
Pear
print
Peach
print
4.基类程序代码// 基类: 水果类
class Fruit
{
public:
void print() {
cout<< "水果" <<endl; }
};
// 派生类1: 香蕉类
class Banana: public Fruit{ public:
void print() {
cout<< "香蕉" <<endl;
} };
// 派生类2: 苹果类
class Apple: public Fruit{ public:
void print() {
cout<< "苹果" <<endl;
} };
派生类程序代码
// 派生类3: 梨子类
class Pear: public Fruit{ public:
void print() { cout<< "梨子" <<endl;
} };
// 派生类4: 桃子类
class Peach: public Fruit{ public:
void print() { cout<< "桃子" <<endl;
} };
#include <iostream> using namespace std; <5个类的定义在此!>
int main() // 主函数 {
核心代码在此!
return 0; }
主函数程序代码
Fruit * pFruit[] = { new Fruit(),
new Banana(), new Apple(), new Pear(), new Peach() };
for(int i = 0; i < 5; i++) { (*pFruit[i]).print(); }
❝
从以上5行运行结果来看,似乎调用的都是基类的print 函数。
❝
究其原因是派生类函数未能覆盖基类同名函数,从而造成没有机会调用派生类函数的情况。
5.运行结果与程序分析
6. 延伸思考
问题
怎样实现派生类函数的调用呢?
答案
使用virtual修饰符改写基
类Fruit的print为虚函数
!
详细格式
virtual void print ()
修改后的基类程序代码// 基类: 水果类
class Fruit
{
public:
virtual void print() {
cout<< "水果" <<endl;
}
};
7.小结
✓虚函数是多态的一种实现形式;
✓作用是实现函数的覆盖;
✓写法是将virtual加在函数之前;
✓今后在类的继承当中的基类尽量多使用虚函数。