实验八 虚函数及应用
虚函数、纯虚函数的多态性机制分析及应用

虚函数、纯虚函数的多态性机制分析与应用内容提要在面向对象程序设计中,继承性映射了现实世界中事物之间的层次现象,而多态性则是要映射事物自身行为的多外延现象;虚函数可以实现不同的对象在收到相同的消息时,产生不同的动作,重载是同一对象在收到相同的消息时,产生不同的动作。
本文对虚函数、纯虚函数的多态性机制进行深入分析,并给出一个应用实例。
关键词动态联编虚函数多态性一. 引言C++可以支持两种多态性:静态多态性和动态多态性。
我们知道,程序在运行前的编译连接阶段会根据源程序中的要调用的函数名用物理地址取而代之,我们称为静态联编,它支持的多态性称为静态多态性。
在调用重载函数时,编译程序在编译阶段就确定了应该调用哪个函数。
动态联编是在程序运行当中才完成的联编。
比如,一个具有多态性的函数运行当中得到了具体对象,该函数这时才可能与某个正确的函数联系起来。
动态联编,支持的多态性称为动态多态性。
虚函数机制就是用来实现动态多态性的利器,我们可以通过基类的指针或引用来访问派生类中对基类重定义的成员函数,之就是运行时多态即动态多态性。
二.虚函数二. 有了虚函数,就使得动态联编成为可能,就可以基类和派生类之间实现动态多态性。
我们在程序代码中使用virtual来指明某个成员函数是虚函数。
虚函数的定义格式:virtual〈返回值类型〉〈函数名〉(〈形式参数表〉){<函数体>}其中,virtual是关键字,它定义以该函数是虚函数。
如果编程者把某类中的一个或多个成员函数定义为虚函数,那么该成员函数在派生类中必有不同的实现代码。
包含虚函数的基类生成派生类时,派生类重新定义该虚函数为自己的目的服务。
假设一个类函数的调用并不能在编译时刻被静态地确定,而只能是在运行时刻被确定,即编写代码的时候并不能确定被调用的是基类的函数还是哪个派生类的函数,必须由系统在运行当中动态地判定,那么就要选择虚函数机制了。
一句话,虚函数机制是动态联编的基础,是实现动态多态性的前提。
C++中虚函数的作用和虚函数的工作原理

C++中虚函数的作⽤和虚函数的⼯作原理1 C++中虚函数的作⽤和多态虚函数:实现类的多态性关键字:虚函数;虚函数的作⽤;多态性;多态公有继承;动态联编C++中的虚函数的作⽤主要是实现了多态的机制。
基类定义虚函数,⼦类可以重写该函数;在派⽣类中对基类定义的虚函数进⾏重写时,需要在派⽣类中声明该⽅法为虚⽅法。
当⼦类重新定义了⽗类的虚函数后,当⽗类的指针指向⼦类对象的地址时,[即B b; A a = &b;] ⽗类指针根据赋给它的不同⼦类指针,动态的调⽤⼦类的该函数,⽽不是⽗类的函数(如果不使⽤virtual⽅法,请看后⾯★*),且这样的函数调⽤发⽣在运⾏阶段,⽽不是发⽣在编译阶段,称为动态联编。
⽽函数的重载可以认为是多态,只不过是静态的。
注意,⾮虚函数静态联编,效率要⽐虚函数⾼,但是不具备动态联编能⼒。
★如果使⽤了virtual关键字,程序将根据引⽤或指针指向的对象类型来选择⽅法,否则使⽤引⽤类型或指针类型来选择⽅法。
下⾯的例⼦解释动态联编性:class A{private:int i;public:A();A(int num) :i(num) {};virtual void fun1();virtual void fun2();};class B : public A{private:int j;public:B(int num) :j(num){};virtual void fun2();// 重写了基类的⽅法};// 为⽅便解释思想,省略很多代码A a(1);B b(2);A *a1_ptr = &a;A *a2_ptr = &b;// 当派⽣类“重写”了基类的虚⽅法,调⽤该⽅法时// 程序根据指针或引⽤指向的 “对象的类型”来选择使⽤哪个⽅法a1_ptr->fun2();// call A::fun2();a2_ptr->fun2();// call B::fun1();// 否则// 程序根据“指针或引⽤的类型”来选择使⽤哪个⽅法a1_ptr->fun1();// call A::fun1();a2_ptr->fun1();// call A::fun1();2. 虚函数的底层实现机制实现原理:虚函数表+虚表指针关键字:虚函数底层实现机制;虚函数表;虚表指针编译器处理虚函数的⽅法是:为每个类对象添加⼀个隐藏成员,隐藏成员中保存了⼀个指向函数地址数组的指针,称为虚表指针(vptr),这种数组成为虚函数表(virtual function table, vtbl),即,每个类使⽤⼀个虚函数表,每个类对象⽤⼀个虚表指针。
多态性与虚函数实验报告

cout<<"三角形的底为:"<<width<<"高为:"<<height <<"面积为:"<<width*height/2<<endl;
}
private:
float width,height;
};
class Circle:public Base
{
public:
Circle(float r){radius = r;}
p= &obj1;
p->area();
p=&obj2;
p->area();
return 0;
}
【实验结果与数据处理】
【实验结论】
分析:用虚函数实现多态。
【实验器材】
微型计算机、Visual C++ 6.0集成软件平台
【实验步骤】
1.编辑源程序。
2.对源程序进行编译并调试程序。
3.连接并运行程序。
4.检查输出结果是否正确。程序设计如下:
#include<iostream.h>
const float PI = 3.14;
class Base
多态性与虚函数实验报告
实验题目
多态性与虚函数
日期
班级
组别
姓名
类型
【实验目的】
1.理解多态性的概念。
2.了解编译时的多态和运行时的多态。
3.掌握虚函数的定义及实现,掌握虚析构函数的使用方法。
4.了解纯虚函数和抽象类的关系及用法。
【实验原理】
设计一个基类Base,其作用是计算一个图形的面积,它只有一个公有的函数成员虚函数area。再从Base类公有派生一个三角形类Triangle和一个圆类Circle,在类Triangle和类Circle中分别定义自己的area函数,用于计算各自的面积。在主函数中设计一个Base类的对象指针,分别指向类Triangle和类Circle的对象,调用各自的area函数显示相应对象的面积。
多态性与虚函数实验报告

多态性与虚函数实验报告实验目的:通过实验掌握多态性和虚函数的概念及使用方法,理解多态性实现原理和虚函数的应用场景。
实验原理:1.多态性:多态性是指在面向对象编程中,同一种行为或者方法可以具有多种不同形态的能力。
它是面向对象编程的核心特性之一,能够提供更加灵活和可扩展的代码结构。
多态性主要通过继承和接口来实现。
继承是指子类可以重写父类的方法,实现自己的特定行为;接口是一种约束,定义了类应该实现的方法和属性。
2.虚函数:虚函数是在基类中声明的函数,它可以在派生类中被重新定义,以实现多态性。
在类的成员函数前面加上virtual关键字,就可以将它定义为虚函数。
当使用基类指针或引用调用虚函数时,实际调用的是派生类的重写函数。
实验步骤:1. 创建一个基类Shape,包含两个成员变量color和area,并声明一个虚函数printArea(用于打印面积。
2. 创建三个派生类Circle、Rectangle和Triangle,分别继承Shape类,并重写printArea(函数。
3. 在主函数中,通过基类指针分别指向派生类的对象,并调用printArea(函数,观察多态性的效果。
实验结果与分析:在实验中,通过创建Shape类和派生类Circle、Rectangle和Triangle,可以实现对不同形状图形面积的计算和打印。
当使用基类指针调用printArea(函数时,实际调用的是派生类的重写函数,而不是基类的函数。
这就是多态性的实现,通过基类指针或引用,能够调用不同对象的同名函数,实现了对不同对象的统一操作。
通过实验1.提高代码的可扩展性和灵活性:通过多态性,可以将一类具有相似功能的对象统一管理,节省了代码的重复编写和修改成本,增强了代码的可扩展性和灵活性。
2.简化代码结构:通过虚函数,可以将各个派生类的不同行为统一命名为同一个函数,简化了代码结构,提高了代码的可读性和维护性。
3.支持动态绑定:通过运行时的动态绑定,可以根据对象的实际类型来确定调用的函数,实现了动态绑定和多态性。
RTTI、虚函数和虚基类的实现方式、开销分析及使用指导

RTTI、虚函数和虚基类的实现方式、开销分析及使用指导由上图得到每种特性的运行时开销如下:可见,关于老天“饿时掉馅饼、睡时掉老婆”等美好传说纯属谣言。
但凡人工制品必不完美,总有设计上的取舍,有其适应的场合也有其不适用的地方。
C++中的每个特性,都是从程序员平时的生产生活中逐渐精化而来的。
在不正确的场合使用它们必然会引起逻辑、行为和性能上的问题。
对于上述特性,应该只在必要、合理的前提下才使用。
"dynamic_cast" 用于在类层次结构中漫游,对指针或引用进行自由的向上、向下或交叉强制。
"typeid" 则用于获取一个对象或引用的确切类型,与 "dynamic_cast" 不同,将 "typeid" 作用于指针通常是一个错误,要得到一个指针指向之对象的type_info,应当先将其解引用(例如:"typeid(*p);")。
一般地讲,能用虚函数解决的问题就不要用"dynamic_cast",能够用 "dynamic_cast" 解决的就不要用 "typeid"。
比如:voidrotate(IN const CShape& iS){if (typeid(iS) == typeid(CCircle)){// ...}else if (typeid(iS) == typeid(CTriangle)){// ...}else if (typeid(iS) == typeid(CSqucre)){// ...}// ...}以上代码用 "dynamic_cast" 写会稍好一点,当然最好的方式还是在CShape里定义名为 "rotate" 的虚函数。
虚函数是C++众多运行时多态特性中开销最小,也最常用的机制。
多态性和虚函数 实验报告

淮海工学院计算机科学系实验报告书课程名:《 C++程序设计(二)》题目:多态性和虚函数班级:学号:姓名:1、实验内容或题目(1)声明二维坐标类作为基类派生圆的类,把派生类圆作为基类,派生圆柱体类。
其中,基类二维坐标类有成员数据:x、y坐标值;有成员函数:构造函数实现对基类成员数据的初始化、输出的成员函数,要求输出坐标位置。
派生类圆类有新增成员数据:半径(R);有成员函数:构造函数实现对成员数据的初始化、计算圆面积的成员函数、输出半径的成员函数。
派生圆柱体类新增数据有高(H);新增成员函数有:构造函数、计算圆柱体体积的函数和输出所有成员的函数。
请完成程序代码的编写、调试。
(2)教材393页7-8题。
(3)教材416页1、4、5题。
2、实验目的与要求(1)理解继承与派生的概念(2)掌握通过继承派生出一个新的类的方法(3)了解多态性的概念(4)了解虚函数的作用与使用方法3、实验步骤与源程序⑴实验步骤先定义一个基类point,及其成员函数,然后以public的继承方式定义子类circle,再定义一个派生类cylinder,最后在main主函数中定义类对象,调用函数实现其功能。
先定义一个基类A及其重载的构造函数,然后以Public派生出子类B,再定义其构造函数,最后在main主函数中定义类对象,调用成员函数实现其功能。
⑵源代码1.#include <iostream.h>class Point{public:Point(float=0,float=0);void setPoint(float,float);float getX() const {return x;}float getY() const {return y;}friend ostream & operator<<(ostream &,const Point &); protected:float x,y;};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){cout<<"["<<p.x<<","<<p.y<<"]"<<endl;return output;}class Circle:public Point{public:Circle(float x=0,float y=0,float r=0);void setRadius(float);float getRadius() const;float area () const;friend ostream &operator<<(ostream &,const Circle &); protected:float radius;};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){cout<<"Center=["<<c.x<<","<<c.y<<"], r="<<c.radius<<", area="<<c.area()<<endl;return output;}class Cylinder:public Circle{public:Cylinder (float x=0,float y=0,float r=0,float h=0);void setHeight(float);float getHeight() const;float area() const;float volume() const;friend ostream& operator<<(ostream&,const Cylinder&);protected:float height;};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){cout<<"Center=["<<cy.x<<","<<cy.y<<"], r="<<cy.radius<<", h="<<cy.height <<"\narea="<<cy.area()<<", volume="<<cy.volume()<<endl;return output;}int main(){Cylinder cy1(3.5,6.4,5.2,10);cout<<"\noriginal cylinder:\nx="<<cy1.getX()<<", y="<<cy1.getY()<<", r=" <<cy1.getRadius()<<", h="<<cy1.getHeight()<<"\narea="<<cy1.area()<<", volume="<<cy1.volume()<<endl;cy1.setHeight(15);cy1.setRadius(7.5);cy1.setPoint(5,5);cout<<"\nnew cylinder:\n"<<cy1;Point &pRef=cy1;cout<<"\npRef as a point:"<<pRef;Circle &cRef=cy1;cout<<"\ncRef as a Circle:"<<cRef;return 0;}2.(1)#include <iostream>using namespace std;class A{public:A(){a=0;b=0;}A(int i){a=i;b=0;}A(int i,int j){a=i;b=j;}void display(){cout<<"a="<<a<<" b="<<b;} private:int a;int b;};class B : public A{public:B(){c=0;}B(int i):A(i){c=0;}B(int i,int j):A(i,j){c=0;}B(int i,int j,int k):A(i,j){c=k;}void display1(){display();cout<<" c="<<c<<endl;}private:int c;};int main(){B b1;B b2(1);B b3(1,3);B b4(1,3,5);b1.display1();b2.display1();b3.display1();b4.display1();return 0;}(2)#include <iostream>using namespace std;class A{public:A(){cout<<"constructing A "<<endl;} ~A(){cout<<"destructing A "<<endl;} };class B : public A{public:B(){cout<<"constructing B "<<endl;} ~B(){cout<<"destructing B "<<endl;} };class C : public B{public:C(){cout<<"constructing C "<<endl;}~C(){cout<<"destructing C "<<endl;}};int main(){C c1;return 0;}3.(1)//Point.hclass Point{public:Point(float=0,float=0);void setPoint(float,float);float getX() const {return x;}float getY() const {return y;}friend ostream & operator<<(ostream &,const Point &); protected:float x,y;}//Point.cppPoint::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<<"]"<<endl;return output;}//Circle.h#include "point.h"class Circle:public Point{public:Circle(float x=0,float y=0,float r=0);void setRadius(float);float getRadius() const;float area () const;friend ostream &operator<<(ostream &,const Circle &);protected:float radius;};//Circle.cppCircle::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<<"Center=["<<c.x<<","<<c.y<<"], r="<<c.radius<<", area="<<c.area()<<endl;return output;}//Cylinder.h#include "circle.h"class Cylinder:public Circle{public:Cylinder (float x=0,float y=0,float r=0,float h=0);void setHeight(float);float getHeight() const;float area() const;float volume() const;friend ostream& operator<<(ostream&,const Cylinder&);protected:float height;};//Cylinder.cppCylinder::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<<"Center=["<<cy.x<<","<<cy.y<<"], r="<<cy.radius<<", h="<<cy.height<<"\narea="<<cy.area()<<", volume="<<cy.volume()<<endl;return output;}//main.cpp#include <iostream.h>#include "cylinder.h"#include "point.cpp"#include "circle.cpp"#include "cylinder.cpp"int main(){Cylinder cy1(3.5,6.4,5.2,10);cout<<"\noriginal cylinder:\nx="<<cy1.getX()<<", y="<<cy1.getY()<<", r=" <<cy1.getRadius()<<", h="<<cy1.getHeight()<<"\narea="<<cy1.area()<<", volume="<<cy1.volume()<<endl;cy1.setHeight(15);cy1.setRadius(7.5);cy1.setPoint(5,5);cout<<"\nnew cylinder:\n"<<cy1;Point &pRef=cy1;cout<<"\npRef as a point:"<<pRef;Circle &cRef=cy1;cout<<"\ncRef as a Circle:"<<cRef;return 0;}(2)#include <iostream>using namespace std;class Shape{public:virtual double area() const =0;class Circle:public Shape{public:Circle(double r):radius(r){} virtual double area() const {return 3.14159*radius*radius;}; protected:double radius;};class Rectangle:public Shape{public:Rectangle(double w,double h):width(w),height(h){} virtual double area() const {return width*height;} protected:double width,height; };class Triangle:public Shape{public:Triangle(double w,double h):width(w),height(h){} virtual double area() const {return 0.5*width*height;} protected:double width,height; };void printArea(const Shape &s)cout<<s.area()<<endl;} int main(){Circle circle(12.6);cout<<"area of circle =";printArea(circle);Rectangle rectangle(4.5,8.4);cout<<"area of rectangle =";printArea(rectangle);Triangle triangle(4.5,8.4);cout<<"area of triangle =";printArea(triangle);return 0;}(3)#include <iostream>using namespace std;class Shape{public:virtual double area() const =0;};class Circle:public Shape{public:Circle(double r):radius(r){}virtual double area() const {return 3.14159*radius*radius;}; protected:double radius;class Square:public Shape{public:Square(double s):side(s){}virtual double area() const {return side*side;}protected:double side;};class Rectangle:public Shape{public:Rectangle(double w,double h):width(w),height(h){}virtual double area() const {return width*height;}protected:double width,height; };class Trapezoid:public Shape{public:Trapezoid(double t,double b,double h):top(t),bottom(t),height(h){} virtual double area() const {return 0.5*(top+bottom)*height;} protected:double top,bottom,height;};class Triangle:public Shapepublic:Triangle(double w,double h):width(w),height(h){}virtual double area() const {return 0.5*width*height;} protected:double width,height;};int main(){Circle circle(12.6);Square square(3.5);Rectangle rectangle(4.5,8.4);Trapezoid trapezoid(2.0,4.5,3.2);Triangle triangle(4.5,8.4);Shape *pt[5]={&circle,&square,&rectangle,&trapezoid,&triangle};double areas=0.0;for(int i=0;i<5;i++){areas=areas+pt[i]->area();}cout<<"totol of all areas="<<areas<<endl;return 0;}4、测试数据与实验结果(可以抓图粘贴)5、结果分析与实验体会继承时,子类对基类的访问属性,基类的私有成员无论以何种方式继承在子类中都是不可访问的,唯有调用基类中的成员函数方可访问其私有变量。
实验8 多态--虚函数

实验八多态—虚函数实验目的:1.学习为什么要使用虚函数。
2.学习如何声明函数为虚函数。
3.学习如何声明异类数组(类型为基类指针,指针分别指向不同的子类对象)。
4.学习如何使用虚函数和异类数组实现多态调用。
实验内容(与实验六相同):创建一个银行账户的继承层次,表示银行的所有客户账户。
所有的客户都能在他们的银行账户存钱,取钱,但是账户也可以分成更具体的类型。
例如,一方面存款账户SavingsAccount依靠存款生利,另一方面支票账户CheckingAccount 对每笔交易(即存款或取款)收取费用。
创建一个类层次,以Account作为基类,SavingsAccount和CheckingAccount 作为派生类。
基类Account应该包括一个double类型的数据成员balance,表示账户的余额。
该类应当提供三个成员函数。
成员函数credit可以向当前余额加钱;成员函数debit负责从账户中取钱,并且保证账户不会被透支。
如果提取金额大于账户金额,函数将保持balance不变,并打印信息“Debit amount exceeded account balance”;成员函数getBalance则返回当前balance的值。
派生类SavingsAccount不仅继承了基类Account的功能,而且还应提供一个附加的double类型数据成员interestrate表示这个账户的比率(百分比)。
SavingsAccount的构造函数应接受初始余额值和初始利率值,还应提供一个public成员函数calculateInterest,返回代表账户的利息的一个double值,这个值是balance和interestrate的乘积。
注意:类SavingsAccount应继承成员函数credit 和debit,不需要重新定义。
派生类CheckingAccount不仅继承了基类Account的功能,还应提供一个附加的double类型数据成员表示每笔交易的费用。
实验八 多态的应用

实验六虚函数与多态性
一、实验目的和要求
1.理解静态多态性和动态多态性。
2.掌握运算符重载的基本方法。
3.掌握虚函数的定义与使用方法。
二、实验内容
1.定义一个类Animal,该类中可以存放动物的名字,并有一个show函数用于显示动物的信息。
定义两个类Cat和Dog,都继承自Animal,重新定义show函数,不但要显示猫对象和狗对象的品种,还要显示动物的名字。
定义一个Tiger类,继承自Cat,重新定义show函数,显示老虎种类和名字。
2、模拟定义存折类,并派生出信用卡类;在存折类中提供可以实现开户,存款、取款和查询余额的函数,要求取款金额必须小于余额;信用卡类对取款操作进行修改,允许透支一定金额;在main()函数中定义对象,模拟生活中存折和信用卡的使用过程。
3.利用第一题中的各种动物,定义一个动物园类Zoo,管理动物,根据下面的提示编写动物类的相关函数。
注意指针的用法。
class Zoo
{
public:
Zoo( int max);//构造函数,max为最多能圈养的动物数
~Zoo(){delete residents};//析构函数
int Accept(Animal *d);//接受动物
void ListAnimals();//显示动物园所有的动物
private:
int maxanimals;//动物园最多能圈养的动物数
int numanimals;//动物园当前圈养的动物数
Animal **residents;//指向动物园全员的动物对象的指针数
};。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验八虚函数及应用一、实验目的1.理解虚函数与运行时(动态)多态性之间的关系,掌握虚函数的定义及应用;2.理解纯虚函数与抽象类的概念,掌握抽象类的定义及应用;3.理解虚析构函数的概念及作用。
二、实验学时课内实验:2课时课外练习:2课时三本实验涉及的新知识㈠虚函数与动态多态性在C++中,如果将基类与派生类的同名成员函数定义为虚函数,就可以定义一个基类指针,当基类指针指向基类对象时访问基类的成员函数,当基类指针指向派生类对象时访问派生类的成员函数,实现在运行时根据基类指针所指向的对象动态调用成员函数,实现动态多态性。
换句话说,虚函数与派生类相结合,使C++能支持运行时(动态)多态性,实现在基类中定义派生类所拥有的通用“接口”,而在派生类中定义具体的实现方法,即“一个接口,多种方法”。
㈡虚函数的定义1.在基类中定义在定义函数的前面加上“virtual ”。
即:virtual 返回类型函数名(参数表){ …… }2.在派生类中定义函数的返回类型、函数名、参数的个数、参数类型及顺序必须与基类中的原型完全相同。
3.说明:⑴在派生类中定义虚函数时,可用“virtual”也可不用“virtual”(最好都使用)。
⑵虚函数在派生类中重新定义时,其原型必须与基类中相同。
⑶必须用基类指针访问虚函数才能实现运行时(动态)多态性;当用普通成员函数的调用方法(即用圆点运算符)调用虚函数时,为静态调用;⑷虚函数在自身类中必须声明为成员函数(不能为友元函数或静态成员函数),但在另一个类中可以声明为友元函数。
⑸虚函数可以公有继承多次,其虚函数的特性不变。
⑹构造函数不能定义为虚函数,但析构函数可以定义为虚函数。
⑺虚函数与重载函数的关系①普通函数重载是通过参数类型或参数的个数不同实现的;重载一个虚函数时,其函数原型(返回类型、参数个数、类型及顺序)完全相同。
②当重载的虚函数只有返回类型不同时,系统将给出错误信息;如果定义的虚函数只有函数名相同,而参数个数或类型不同时,则为普通函数重载。
㈢纯虚函数与抽象类1.纯虚函数定义格式:virtual 返回类型func_name(参数表)=0;[ { …… } ]2.抽象类⑴抽象类的概念当一个类中定义了一个或多个纯虚函数,则该类称为抽象类。
⑵说明:①抽象类中包含没有功能的纯虚函数,用来提供派生类的公共接口函数。
因此,抽象类只能作为其它类的基类,不能定义其对象。
②可以定义抽象类的指针或引用,用于指向派生类而实现多态性。
③如果在派生类中未重新定义纯虚函数,则派生类只是继承了基类的纯虚函数,这时,派生类仍是抽象类。
㈣虚析构函数1.虚析构函数的定义在析构函数名前加上“virtual”。
即:virtual ~ 类名(void){ …… }2.说明当类中需要显式定义析构函数,而在基类中定义了虚函数时,应将析构函数定义为虚析构函数,以实现动态调用析构函数。
四、实验内容㈠验证及认知实验按要求调试下列程序,并回答相关问题。
程序1(exp_801.cpp)#include <iostream.h>class Base{ int a,b;public :Base(int x,int y){a=x;b=y;}void show(){ cout <<"a="<<a<<" b="<<b; }};class Derived:public Base{ int c;public:Derived(int x,int y,int z):Base(x,y){c=z;}void show(){ Base::show();cout <<" c="<<c;}};{Base mb(50,50),*mp;Derived md(10,20,30);mp=&mb; mp->show();cout<<endl;mp=&md; mp->show();cout<<endl;((Derived*)mp)->show();cout<<endl;}问题:⑴编译运行程序的输出结果为:⑵根据程序的输出结果可知:执行“mp=&mb; mp->show();”时,调用的是类的show() ;执行“mp=&md; mp->show();”时,调用的是类的show() ;执行“((Derived*)mp)->show();”时,调用的是类的show() ;其中“((Derived*)mp)”是将Base类“mp”指针强制转换为类的指针。
⑶在基类“Base”中的成员函数“void show()”改为“virtual void show()”,再重新编译运行程序,输出结果为:⑷当执行“mp=&md; mp->show();”时,调用的是类的show() ;函数“show()”称为,实现了多态性。
程序2(exp_802.cpp)#include <iostream.h>class Base{ public :virtual void show(){ cout<<"Base该类无计算"<<endl; }};class Derived1:public Base{ int a ;public:Derived1(int x){a=x;}{ cout <<"a="<<a<<endl; }};class Derived2:public Base{ int b ;public:Derived2(int x){b=x;}void show(){ cout <<"b="<<b<<endl; }};void main(){Base mb;Base *mp;Derived1 md1(10);Derived2 md2(20);mp=&mb; mp->show();mp=&md1; mp->show();mp=&md2;mp->show();}问题:⑸编译运行程序的输出结果为:⑹将“Base”类中的“virtual void show()”改为“virtual void show()=0”,重新编译程序会出现,其中的“show() ”称为虚函数,该类称为类,出错原因是。
⑺去掉main()函数中的“Base mb;”及“mp=&mb; mp->show();”,重新编译运行程序的输出结果为:㈡知识应用实验1.分析下列程序,写出程序的输出结果,再上机运行程序验证其正确性,如果不正确,请认真分析出错原因。
程序3(exp_803.cpp)#include <iostream.h>class parent{protected :char version;public:parent(){version='A';}virtual void print(){cout <<"\n The parent. version "<<version;}};class derived1:public parent{private:int info;public:derived1(int number){info=number;version='1';}void print(){cout<<"\n The derived 1 info:"<<info<<" version "<<version;} };class derived2:public parent{private:int info;public:derived2(int number){info=number; }void print(){cout<<"\n The derived 2 info:"<<info<<" version "<<version;}};void main(){parent ob,*op;op=&ob;op->print();derived1 d1(3);op=&d1;op->print();derived2 d2(15);op=&d2;op->print();cout <<endl;}程序4(exp_804.cpp)#include <iostream.h>class base1{ public:virtual void fun(){cout <<"----base1----"<<endl;} 你分析的程序输出结果是:程序的实际输出结果是:};class base2{ public:virtual void fun(){cout <<"----base2----"<<endl;}};class derived:public base1,public base2{ public :void fun(){cout <<"----derived----"<<endl;}};void main(){ base1 ob1,*p1;base2 ob2,*p2;derived ob3;p1=&ob1; p1->fun();p2=&ob2; p2->fun();p1=&ob3; p1->fun();p2=&ob3; p2->fun();}程序5(exp_805.cpp )#include <iostream.h>class figure{ protected :double x,y;public :figure(double a,double b){x=a;y=b;}virtual void show_area( ){ cout <<"No area computation defined"; cout <<" for this class.\n"; }};class triangle:public figure{ public:triangle(double a,double b):figure(a,b){ } ;void show_area(){ cout<<"Triangle with height "<<x; cout<<" and base "<<y<<" has an area of";cout<<0.5*x*y<<endl;}};class square:public figure { public :你分析的程序输出结果是: 程序的实际输出结果是:square(double a,double b):figure(a,b){ };void show_area(){ cout <<"Square with dimension "<<x;cout <<" * "<<y<<" has an area of ";cout <<x*y<<endl;}};class circle:public figure{ public:circle(double a):figure(a,a){ };void show_area(){cout <<"Circle with radius "<<x;cout <<" has an area of "; cout <<x*x*3.141593<<endl;}};void main(){figure *p;triangle t(10.0,6.0);square s(10.0,6.0);circle c(10.0);p=&t; p->show_area();p=&s; p->show_area();p=&c; p->show_area();} 2.完善、调试通过下列程序,并按所要求回答问题。