实验5-多态性与虚函数-程序.doc
C--程序设计--第10章-多态性及虚函数
使用重载函数注意:
不要使用重载函数描述不相干的函数 在类中,构造函数和普通成员函数均可以
重载 避免与函数的默认参数产生二义性
二、运算符重载
运算符重载(operate overloading)就是 赋予已有的运算符多重含义。
运算符重载实质是函数重载,运算符重载 的选择与函数重载类似,会根据运算符的 操作数的类型、个数和顺序来进行运算符 函数的选择。
#include<iostream.h> str#iinngc:l:usdter<isntgr(icnhga.rh>*s) v{}ossccsssc{s{{ittohtttolsstlsssls*drruarrrueptrepttepsi1trii3tc{pn=rin=rrn=pmn.<nn.<lprgncngncign=agp<*ggp<auitepgtepnte'irssrssbv\hwy:hwyghwnsit1ssitsla0=(:=(:=(tnr=ttnrit'scssscs:sc)rt1"rrt3scesss~ivci;thpt1hpsih1(.T23(.t::tttsnohn}ra,r.a,tza()gh(()grrrrttiatlrsilrsrer";eass;eiiiirdre[)ne[1i;[Ttt1ttnnnniglnl;gnl.nlhl)rlggggnep*e(e}(gesgeiei;2e(((gtrsnsnstnp(nsns)ncsi(lipg)gthg)ig(;(htn)en;t;tr;t;nti)a)artnthhih}ths<<ri{((;+n++<p<snd))}1g1s1aere*ige;]]i]nonszl{{;&;z;ddgd)&eercseelrl;s=teo1)m;a;/18etu)om/)0ut..;)构sr<""/;pn<造);//;s;/复}lp函构e<制n<数造ge构tn函hd造;l数};重} 载
多态性与虚函数实验报告
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、掌握初始化基类成员的方法。
3、掌握派生类对基类的继承。
4、学习虚函数和纯虚函数的定义与使用方式。
5、理解抽象类的概念,学习如何用指针指向其他的派生类,实现多态性。
6、掌握抽象类的定义与使用方式,并注意指针的用法。
7、学习如何使用虚函数、纯虚函数、抽象类和实现类的多态性。
二、实验设备与平台实验设备要求每个学生一台电脑,其中运行环境为VC++ 6.0系统或新版。
三、实验内容与步骤实验:编写一个人员信息管理系统。
这个系统的功能是:交互式地实现校园人员信息的录入与显示。
分析:学校里,主要有四类人员:大学本科学生、教师、研究生和助教。
大学本科生每周有固定的学时数。
教师除了固定的学时数外,还有每周的教学时数。
研究生除了固定的学时数外,每周还可以自由做一定的研究。
助教除了上课外,还要做研究和一定的教学工作。
人员的基本信息包括姓名、编号、性别、身份证号、总学时数、以及每周固定学时数。
各个人员之间的关系:people类派生出student类和teacher类,student类派生出graduate 类,graduate类和teacher类派生出TA类。
以下给出部分程序:#include <iostream>using namespace std;class people{public://添加程序private:};class student: virtual public people{public://添加程序private:};class teacher: virtual public people{public://添加程序private:};class graduate: virtual public student {public://添加程序private:};class TA: public graduate, public teacher {public://添加程序private:};void main(){//添加程序}。
多态性和虚函数
成员函数形式: 返回类型 operator 重载运算符(入口参数表); 友元函数形式: friend 返回类型 operator 重载运算符(入口参数 表);
重载方式示例 class A { A operator +(A&); friend A operator +(A&, A&); };
用成员函数重载运算符: 一般而言,重载一元运算符没有参数;重载 二元运算符只有一个参数。 一般基于某个对象调用成员函数,这个对象 是一个隐含的操作数,就是被调用的运算符函数的 一个操作数,而且是第一操作数 有了运算符重载以后,当程序中出现表达式: “ a = b + c;”的时候编译程序将其解释为: “a = b.operator+( c )";
“绑定”——就是让函数调用与函数体产生 关联。 在编译时就确定——叫“早期绑定”; 在程序运行时才确定——叫“晚期绑定”。 而C++的多态性在“早期绑定”和“晚期绑 定”两方面都有体现。
2 虚函数
虚函数是在基类中使用了关键字virtual 的成员函数。 虚函数与函数重载的区别: 1、虚函数定义在基类和派生类中,函 数原型完全一致; 2、函数重载在同一个类中,或者都在 类外定义,函数原型必定不完全相同。
用友元函数重载运算符: 不是成员函数,也没有this指针,用友元函 数重载二元运算符(双目运算符)时,要有两个参 数;重载一元运算符(单目运算符)时,要有一个 参数。 当程序中出现表达式:“ a = b + c;”的时候 编译程序将其解释为: “a = operator+(b,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、结果分析与实验体会继承时,子类对基类的访问属性,基类的私有成员无论以何种方式继承在子类中都是不可访问的,唯有调用基类中的成员函数方可访问其私有变量。
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,程序中使用了简单的类层次结构来保存作者姓名和书名。
多态性和虚函数
虚函数
程序演示
void printMove(Soldier** sd, int num){ for(int i=0;i<num;i++){ sd[i]-> move(); } } void printAttack(Soldier** sd, int num){ for(int i=0;i<num;i++){ sd[i]-> attack(); } } int main(){ Soldier* sd[10]; for(int i=0;i<10;i++){ sd[i]=new Tauren; i++; sd[i]=new Shaman; } printMove(sd,10); printAttack(sd,10); }
派生类Shaman对象模型:
x y s
Shaman ::move()
Shaman ::attack()
虚函数
内部机制
对象结构(基类中声明虚函数) _vptr
基类Soldier对象模型:
虚函数表 Soldier::move() Soldier::attack()
x
y _vptr
Tauren::move() Tauren::attack()
类型强制转换
1+0.5; 1+2; p+1;(其中p是一个对象)
虚函数
运算符重载
模板
联编(binding)
联编也称为绑定,指把函数体和函数调用 相联系。它分为静态联编和动态联编两种。
静态联编(Static Binding) :程序(函数体和函数调用) 的匹配、连接在编译阶段,即程序运行之前完成,也称 为早期匹配。重载函数使用静态联编。 动态联编(Dynamic Binding) :程序(函数体和函数调用) 的匹配、连接推迟到运行时进行,所以又称为晚期联编。 虚函数使用的是动态联编。
实验6多态性与虚函数
[实验目的]1、了解多态性的概念;2、了解虚函数的用途及使用方法;3、了解纯虚函数和抽象类的概念和用法。
[实验要求]给出以下各实验内容的源程序代码,并把编译、运行过程中出现的问题以及解决方法填入实验报告中,按时上交。
[实验学时]2学时。
[实验内容]1、写一个程序,定义抽象基类Shape,由它派生出3个派生类:Circle(圆形)、Square(正方形)、Rectangle(矩形)。
利用指针、虚函数printArea()分别输出以上三者的面积,3个图形的数据在定义对象时给定。
[源程序]#include<iostream>using namespace std;class Shape{public:virtual float area()const=0;virtual void display()const=0;};class Circle:public Shape{public:Circle(double a):r(a){}virtual float area()const{return 3.14*r*r;}virtual void display()const{cout<<"圆面积"<<area()<<endl;}private:double r;};class Rectangle:public Shape{public:Rectangle(double a,double b):l(a),w(b){}virtual float area()const{return l*w;}virtual void display()const{cout<<"矩形面积"<<area()<<endl;}private:double l;double w;};class Square:public Shape{public:Square(double a):a1(a){}virtual float area()const{return a1*a1;}virtual void display()const{cout<<"正方形面积"<<area()<<endl;}private:double a1;};int main(){Circle c1(5);Rectangle r1(5,8);Square s1(2.5);Shape *p[3]={&c1,&r1,&s1};int i;double m=0.0;for (i=0;i<3;i++){p[i]->display();m=m+p[i]->area();}cout<<"总面积:"<<m<<endl;}2、定义Point(点)类,由Point类派生出Circle(圆)类,再由Circle类派生出Cylinder(圆柱体)类。
多态性和虚函数(精)
void main() { A a, *pa; // pa为基类对象的指针 B b, *pb; // pb为派生类对象的指针 pa=&b; // 基类指针pa指向派生类对象b // 通过基类指针pa访问B中从基类A继承的公有成员 pb=&a pa->setA(100); pa->setB() pa->showA(); pa->showB() pb=(B*)pa; // 将基类指针强制转化为派生类指针 // 不能通过基类指针pa访问派生类自己定义的成员 pb->setB(200); 程序运行结果为: pb->showB(); a=100 } b=200
类B的析构函数,然后再调 用基类A的析构函数。
3.4.3 抽象类和纯虚函数
1. 何谓抽象类
抽象类是类的一些行为(成员函数)没有给 出具体定义的类,即纯粹的一种抽象。 抽象类只能用于类的继承,其本身不能用来 创建对象,抽象类又称为抽象基类。 抽象基类只提供了一个框架,仅仅起着一个 统一接口的作用,而很多具体的功能由派 生出来的类去实现。 虽然不能声明抽象类的对象,但可以声明指 在一般的类库中都使用了抽象 向抽象类的指针。
2. 要将一个成员函数声明为虚函数,只需在 虚函数的声明
定义基类时在成员函数声明的开始位置加上关 键字 virtual 。 class A
{ public: virtual void Show() { cout<<"A::show\n"; }; }; class B : public A { public: void Show() { cout<<"B::show\n"; }; };
3. 联编的概念
最新C++程序设计案例教程精品课件多态性和虚函数
9.1.2 虚函数的使用
运行结果
程序分析
如何通过基类指针调用派生类的同名函数?C++中的虚函数很好地解 决了这个问题。从代码中可以看到,只在基类同名函数声明的前面增 加了关键字virtual,程序运行时,系统就根据指针情况调用了派生类 的同名函数。
知识讲解
虚函数的作用是通过基类指针调用派生类的同名函数。 当基类的一个成员函数被声明为虚函数后,其派生类中的 同名函数都自动成为虚函数。因为基类中已经加了关键字 virtual,所以在声明派生类的同名函数时可以省略关键字。 如果基类中有虚函数,而派生类无同名函数或者派生类没 有对基类的同名函数重新定义,则派生类仍然继承基类的虚 函数。
Click to add Text 案例引入
建立纯虚函数,实现虚函数在派生类中的模板作用。
9.2 纯虚函数和抽象类
源代码展示 #include <iostream> using namespace std; class Graph { public: virtual void display()=0; //定义纯虚函数 }; class Rectangle:public Graph { private: int len,width; public: Rectangle(int l,int w):len(l),width(w){} virtual void display() { cout<<"The rectangle area is
9.1 多态性和虚函数
9.1.1 多态性
分别用对象名和指针变量调用基类和 Add your text in here 派生类中的同名函数
Click to add Text 案例引入
C++面向对象程序设计 第6章 多态性与虚函数
2、实现这种动态的多态性时,必须使用基类类型 、实现这种动态的多态性时,必须使用基类类型 的指针变量,并使该指针指向不同的派生类对象 指向不同的派生类对象, 的指针变量,并使该指针指向不同的派生类对象, 并通过调用指针所指向的虚函数才能实现动态的 多态性。 多态性。
类A x Show () Show()定义为虚函数 定义为虚函数 类B x Show () y Show () 类C x Show () z
class Derive:public Base{ public : int Set(int x, int y) { ..... } ..... }; class Derive:public Base{ public : int Set(int x, int y=0) { ..... } ..... };
虚函数是用关键字virtual修饰的某基类中的 修饰的某基类中的 虚函数是用关键字 protected或public成员函数。它可以在派生 或 成员函数。 成员函数 类中重新定义,以形成不同版本。 类中重新定义,以形成不同版本。只有在程 序的执行过程中, 序的执行过程中,依据指针具体指向哪个类 对象,或依据引用哪个类对象, 对象,或依据引用哪个类对象,才能确定激 活哪一个版本,实现动态聚束。 活哪一个版本,实现动态聚束。
class Point{ float x,y; public: Point(){} Point(float i,float j){ x=i; y=j; } virtual float area(void) { return 0.0; }//声明为虚函数 声明为虚函数 }; 输出: 输出:92.7011 const float Pi=3.14159; 0 class Circle:public Point{ //类Point的派生类 类 的派生类 92.7011 float radius; public: Circle(float r){ radius=r; } float area(void) { return Pi*radius*radius;}//虚函数再定义 虚函数再定义 }; void main(void) { Point *pp; //基类指针,可以将派生类对象的地址赋给基类指针 基类指针, 基类指针 Circle c(5.4321); 用对象名调用area( ) 用对象名调用 cout<<c.area()<<endl; cout<<c.Point::area()<<endl; cout<<c.Circle::area ()<<endl; }
面向对象程序设计之多态性与虚函数详解演示文稿
第3页,共61页。
6.1 多态性的概念
我们其实已经接触过多态性的现象。如函数的重载 多态性分类:从系统实现的角度看,多态性分为以下两类:
静态多态性:又称编译时的多态性。如函数重载属于静态 多态性。
动态多态性:有称为运行时的多态性。它主要表现为虚函 数( virtual function )。
6.4 纯虚函数与抽象类
前面已经提到,有时在基类中将某一成员函数定为虚 函数并不是基类本身的需要,而是派生类的需要。在基类中 预留一个函数名,具体功能留给派生类根据需要去定义。
#include <iostream.h>
#include <string.h>
class student
{public:
student (int n,string nam, float s) { num= n; name= nam; score= s; }
void display( )
{cout<<“num:”<<num <<“name:”<<name
第13页,共61页。
6.3 虚函数
虚析构函数 问题的引出:我们知道,当派生类对象撤消时,系统先调用派生类析构函数, 再调用基类析构函数。但是,如果用new 运算符建立了一个派生类临时对象, 但用一个基类指针指向它,当程序用带指针参数的delete 撤消对象时,会发生 让人不能接受的情况:系统只析d display( ) {cout<<“num:”<<num <<“name:”<<name <<“score:”<<score <<“pay:”<<pay<<endl; }
第13章 多态性和虚函数-文档资料
利用 p,可以通过 B_obj 访问所有从 A_obj 继承的 元素 ,但不能用 p访问 B_obj 自身特定的元素 (除非 用了显式类型转换)。
注意:可以用一个指向基类的指针指向其公有派
生类的对象。但却不能用指向派生类的指针指向一个 基类对象。希望用基类指针访问其公有派生类的特定 成员,必须将基类指针用显式类型转换为派生类指针。 例如((B_class *)p)-> show_phone();一个指 向基类的指针可用来指向从基类公有派生的任何对象, 这一事实非常重要,它是C++实现运行时多态的关键
(6)一个类的虚函数仅对派生类中重定义 的函数起作用,对其他函数没有影响。在基类 中使用虚函数保证了通过指向基类对象的指针 调用基类的一个虚函数时,C++系统对该调用 进行动态绑定,而使用普通函数则是静态绑定。
8.3.3 虚函数与重载函数的比较
(1)重载函数要求函数有相同的返回值类型和函 数名称,并有不同的参数序列;而虚函数则要求这三 项(函数名、返回值类型和参数序列)完全相同;
在程序中不可滥用函数重载,不适当的重载会降低程 序的可读性。C++语言并没有提供任何约束限制重载函数 之间必须有关联,程序员可能用相同的名字定义两个互 不相关的函数。实际上函数重载暗示了一种关联,不应 该重载那些本质上有区别的函数,只有当函数实现的语 义非常相近时才应使用函数重载。
函数重载的二义性
途径。
虚函数
虚函数的概念
虚函数是在基类中冠以关键字 virtual 的成员函数。 它提供了一种接口界面。虚函数可以在一个或多个派 生类中被重定义。
P252程序 :当main()函数的语句1~6随着指针p所指 对象不同而调用不同版本的who()函数时,就实现 了运行时的多态,这种机制的实现依赖于在基类中把 成员函数 who()说明为虚函数。
下载-第五章多态性和虚函数解读
下载-第五章多态性和虚函数解读实验四多态性与虚函数⼀、实验⽬的和要求1 了解多态性在C++中的体现;2 掌握虚函数的应⽤;3 了解抽象类。
⼆、基本概念多态性多态是指同样的消息被不同类型的对象接收时导致不同的⾏为,所谓消息是指对类的成员函数调⽤,不同的⾏为是指不同的实现,也就是调⽤了不同的函数。
多态性可以分为四类:重载多态、强制多态、包含多态和参数多态。
多态从实现的⾓度来讲可以划分为两类:编译时的多态和运⾏时的多态。
编译时的多态性是在编译的过程中确定了同名操作的具体操作对象,也就是通过重载函数来实现的。
运⾏时的多态性是在程序运⾏过程中才动态地确定操作所针对的具体对象,就是⽤虚函数来实现的。
虚函数虚函数是重载的另⼀种表现形式,它是⼀种动态的重载⽅式,它提供了⼀种更为灵活的多态性机制。
虚函数允许函数调⽤与函数体之间的联系在运⾏时才建⽴,也就是在运⾏时才决定如何动作,即所谓的“动态连接”。
⼀般虚函数成员的定义语法是:virtual 函数类型函数名(形参表)虚函数的定义实际就是在原有的普通函数成员前⾯使⽤virtual关键字来限定,虚函数声明只能出现在类定义中的函数原型声明中,⽽不能在成员的函数体中。
运⾏过程中的多态需要满⾜三个条件,⾸先类之间应满⾜赋值兼容规则,其⼆是要声明虚函数,第三是要由成员函数来调⽤或者是通过指针、引⽤来访问虚函数。
抽象类抽象类是⼀种特殊的类,它为⼀族类提供统⼀的操作界⾯。
⼀个抽象类⾃⾝⽆法实例化,也就是说我们⽆法定义⼀个抽象类的对象,只能通过继承机制,⽣成抽象类的⾮抽象派⽣类,然后再实例化。
抽象类是带有纯虚函数的类。
纯虚函数是⼀个基类中说明的虚函数,它在该基类中没有定义具体的操作内容,要求各派⽣类必须根据实际需要定义⾃⼰的版本,纯虚函数的声明格式为:virtual 函数类型函数名(参数表)= 0;声明为纯虚函数之后,基类中就不再给出函数的实现部分,它的实现是在它的派⽣类定义的。
对抽象类使⽤的⼏点规定如下:1 抽象类只能⽤作其他类的基类,不能建⽴抽象类对象;2 抽象类不能⽤作参数类型、函数返回类型或显式转换的类型;3 可以说明指向抽象类的指针和引⽤,此指针可以指向它的派⽣类,进⽽实现多态性⼀般虚函数成员的定义语法是:virtual 函数类型函数名(形参表)纯虚函数的声明格式为:virtual 函数类型函数名(参数表)= 0;三、程序例题例题有⼀个汽车类Vehicle,将它作为基类派⽣出⼩车类Car、卡车为类Truck和轮船类Boat,定义message( )函数⽤来显⽰各类信息。
实验五 虚函数与多态性
实验五 虚函数与多态性(4学时)[实验目的]1、 掌握运算符重载的基本方法;掌握虚函数的定义与使用方法。
2、 理解静态多态性和动态多态性;掌握使用虚函数和继承实现动态多态性的方法。
[实验内容与步骤]1、 定义Pomt 类,包含有坐标x ,y 两个成员变量,对Pomt 类重载运算符 ++(功能:坐标值x ,y 增1)和 --(功能:坐标值x ,y 减1),实现对坐标值的增减。
2、 定义一个车(vehicle )基类,有Run 、Stop 等成员函数,由此派生出自行车(bicycle )类、汽车(motorcar )类,从vehicle 和motorcar 派生出摩托车(motorcycle )类,它们都有Run 、Stop 等成员函数。
观察虚函数的作用。
3、 对实验三中的people 类重载运算符 == 和 = 。
其中,== 用于判断两个people 类对象的id 属性是否相等;= 则实现对people 类对象的赋值操作。
4、 定义矩阵类,重载运算符 + 和 *,实现对矩阵类对象的相加和相乘。
5、 定义一个类BaseFly ,该类中有一个 Fly ()函数。
再定义三个类 BirdFly 、DragonFly 和 PlaneFly ,都继承自 BaseFly ,并重载 Fly ()函数。
用各类指针调用各个类对象的 Fly ()函数,体会继承的多态性。
6、 将 BaseFly ∷Fly( ) 函数声明为 virtual ,体会虚函数在多态性中的作用。
[习题与思考题]1、 建立一个类 convert ,它含有两个私有数据成员 x 与 y ,用于表示直角坐标的位置;另外含有两个私有成员函数getr( )与 getangle( ),用于将直角坐标转换为极坐标。
重载运算符 +,使能执行convert 类对象的相加运算。
直角坐标(x ,y )转换为极坐标(r ,θ)的公式为:πθ180tan 122⨯=+=-x y y x r , 2、 创建字符串类string ,重载运算符 +,使能实现两个字符串的连接;重载运算符 =,使能实现字符串赋值。
多态性和虚函数
2. 虚函数与重载函数的关系
(1) 重载函数要求函数有相同的函数名称,但是形参 的个数或者类型不应相同;而虚函数则要求函数名、 返回值类型和参数完全相同; (2) 重载函数可以是成员函数或友员函数,而虚函数 只能是成员函数; (3) 重载函数的调用是以所传递参数序列的差别作为 调用不同函数的依据;虚函数是根据对象的不同去调 用不同类的虚函数; (4) 虚函数在运行时表现出多态功能,这是C++的精 髓;而重载函数则在编译时表现出多态性。
}; point point::operator +(point q) { return point(x+q.x, y+q.y); }
void main()
{ point p1(3,3), p2(2,2), p3;
p3=p1+p2;或p1. operator +(p2)
//声明point类的对象
6.1.4 几个常用运算符的重载
2.前自增和后自增运算符++的重载
前自增运算符++和后自增运算符++重载的语法
<函数类型>operator++();
//前
<函数类型>operator++(int); //后
课本P147
【例6.7】用成员函数重载前自增和后自增运算符。
【例6.8】用友元重载前自增和后自增
型,运算符重载是对运算符进行重新定义,赋予已有符 号新功能的要求。
不能重载的运算符是: (1) 成员访问运算符. (2) 作用域运算符∷ (3) 条件运算符?: (4) 成员指针运算符* (5) 编译预处理命令的开始符号#
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验5多态性和虚函数二.实验内容5・1 .cpp#inelude <iostream> using namespace std;#inelude <string> class Point{public:Point(int=0, int=0); virtual~Point(){} virtual void set(); virtual void display(); protected:int x,y;};Point::Point(int x, int y){ this->x=x;this->y=y;} void Point::set(){ cout«H Please en ter the in format! on of poin t(x, y):H ; cin> >x»y;}void Point::display(){ class Circle: public Point{public:Circle(int=O, int=0, int=0);~Circle(){}virtual void set(); virtual voiddisplay(); protected:int radius;};Circle::Circle(int x, int y, int radius):Point(x, y){ this->radius=radius; }void Circle::set(){ cout«,,Please en ter the in format! on of Circle(x, y, radius): cin»x»y»radius; }void Circle:: display!){ cout«H x=,,«x«" y=,,«y«n radius=H «radius«e ndl; } class Cylinder: public Circle〃圆柱体类 {public:Cylinder(int=O, int=0, int=0‘ int=0); 〃构造函数〃点类 〃构造函数〃析构函数〃虚函数 〃虚函数 〃坐标点 cout«,,x=,,«x«" y="«y«endl;} 〃圆类 〃构造函数 〃析构函数 〃重新定义熄函数 〃重新定义虚函数 〃圆半径~Cylinder(){}〃析构函数 virtual void set();〃重新定义虚函数 virtual void display));〃重新定义虚函数 protected:int height; 〃圆柱体的高 };Cylinder::Cylinder(int x, int y, int radius, int height): Circle(x, y, radius) { this->height=height; }void Cylinder::set(){ cout«H Please enter the information of Cylinderfx, y, radius, height) :n ;cin> >x>>y»radius»height;} void Cylinder:: display(){ cout«l,x=,,«x«H y=H «y;cout «H radjus=,,«radius«H height=H «height«e ndl;}int main(){Point *p;〃定义基类指针 Point point;〃定义基类对象p=&poi nt;p->display();P->set(); p->display();Cylinder cylinder(O, 0, 3,10); 〃定义派生类对象 p= &cyli nder; p->display();p->set();p->display();return 0;} 5・ 2.cpp#include <iostream> using namespace std;#inelude <string> class Employee {public:Circle circlefO, 0, 3);p 二&circle;p->display();p->set();p->display();〃定义派生类对象〃职工类Employee(char *, char *); virtual~Employee(){} void setName();char* getNamef);void setlD();char* getlD(); virtual float pay()=O;virtual void print()=O; protected:char name[20];char id[20];Employee::Employee(char *name, char*id){ strcpy(this->name, name); strcpy(this->id, id);}void Employee:: setName(){cout «l,Please enter employee's name: H «endl;cin»n ame;}char* Employee:: getName(){ return name; } void Employee:: setlD() {cout «n Please enter employee's ID: H «endl; cin> >id;}char* Employee:: getlD(){ return id; } class Manager: public Employee {public:Manager(char *name 7 char *id, float salaryJiEmployeetname, id) {this->salary=salary;}^ManagerOOfloat pay(){ return salary;}void print(){ cout«endl«H name:”vvname«H ID: "«id«" pay: n «pay()«endl;} private: float salary;};class Technician: public Employee{public:Technician(char ame, char *id, int hours, float wage): Employee(name, id) { this->hours=hours; this->wage=wage; }~Technician(){}float pay(){return hours*wage;}void print)){ cout«endlvv 11 name: ”vvname«H ID: ,,«id«,' pay: n «pay()<vendl;} private:int hours;float wage;};〃构造函数 〃析构函数 〃修改姓名 〃获取姓名 〃修改工号 〃获取工号 〃计算职工的工资 〃输出职工的信息〃姓名 〃工号int main(){ Employee *p;Manager managerf'Zhang", "101", 9000);p=&ma nager;p->print();Technician technicianC'Zhang", "112", 8*29, 30);p=&tech nician;p->print();return 0;}5・ 3.cpp#inelude <cmath>#in clude<iostream>using namespace std;const double Pl=3.1415926535;class Shape 〃形状类{public:virtual void show()=0; 〃纯虚函数virtual double area()=0; 〃纯虚函数};class Rectangle:public Shape 〃矩形类{public:Rectangle(){ length=0; width=0;}Rectangle(double len, double wid){ length= len; width = wid;}double area(){ return length*width;} 〃实现基类屮的纯虚函数area求矩形面积void show() 〃实现基类中的纯虚函数show输出矩形的长和宽{cout«"length="«length«,\t'«"width="«width«endl;}private:double length, width; 〃矩形的长和宽};class Triangle: public Shape 〃三角形类{public:Triangle(){a=O; b=0; c=0;}Triangle(double x, double y, double z){ a = x; b = y; c = z; } double area()〃实现基类中的纯虚函数area 求三角形面积 { double s=(a+b+c)/2.0;return sqrt(s*(s-a)*(s-b)*(s-c));}void show()〃实现基类中的纯虚函数show 输出三角形的三边长 { cout«"a="«a«,\t'«"b="«b«'\t ,«"c="«c«endl; } private:double a, b, c; 〃三角形的三边长};class Circle: public Shape 〃圆类{public:Circle(){radius = 0;}Circle(double r){radius = r;}double area() {return Pl*radius*radius;}〃实现基类中的纯虚函数area 求圆面积 void show(){cout«"radius="«radius«endl;}//实现基类中的纯虚函数show 输出圆半径 private:double radius; 〃圆半径}; void total(Shape *p[], int n) { double sum=0;for (int i=0; ivn; i++) sum+=p[i]->area();cout«"图形面积总和二"«sum«endl; } int main() 〃定义基类指针s 〃定义Circle 类对象c 〃定义Rectangle 类对象r〃定义Triangle 类对象t〃静态多态cout«"圆面积:"«c.area()«endl;s=&r;〃动态多态 s->show();coutvv”矩形面积:"«s->area()«endl; s=&t; 〃动态多态 s->show();cout«'三角形面"«s->area()«endl;Shape *p[]={&c, &r, &t}; 〃定义基类指针数组P ,使其每一个元素指向一个派生类对象 total(p,3); return 0;} Shape *s;Circle c(10);Rectangle r(6, 8); Triangle t(3, 4, 5); c.show();。