实验8 多态性与虚函数
第8章 多态性和虚函数
第8章多态性和虚函数封装性基础面向对象系统三特征继承性关键多态性补充多态性是指发出同样的消息被不同类型的对象接收时导致完全不同的行为。
这里所说的消息主要是指对类的成员函数的调用,而不同的行为是指不同的实现。
利用多态性,用户只需发送一般形式的消息,而将所有的实现留给接收消息的对象。
多态的类型:简单的多态性是函数重载和运算符重载。
重要的多态性是建立在虚函数的概念和方法上的。
8.1 函数重载8.2 运算符重载运算符重载就是赋予已有的运算符多重含义,使它能够用对类的对象进行特定的操作。
8.2.1运算符重载的几个问题1.C++中不能重载的运算符是:. , .* ,:: , ?:2.运算符重载不改变原运算符的优先级和结合性。
3.编译程序对运算符重载的选择,遵循函数重载的原则。
4.重载运算符的限制:(1)不可臆造新的运算符。
(2)重载运算符坚持4个“不能改变”。
·不能改变运算符操作数的个数;·不能改变运算符原有的优先级;·不能改变运算符原有的结合性;·不能改变运算符原有的语法结构。
5.运算符重载时必须遵循哪些原则:(1)重载运算符含义必须清楚。
(2)重载运算符不能有二义性。
8.2.2 运算符重载的两种形似运算符重载的两种形式:成员函数形式和友元函数形式。
1.重载为类的成员函数例8.2复数类四则运算重载#include<iostream.h>class complex{ public:complex( ) { real=imag=0; }complex(double r, double i){real=r,imag=i;}complex operator +(const complex &c);complex operator -(const complex &c);complex operator *(const complex &c);complex operator /(const complex &c);friend void print(const complex &c);private:double real,imag;};inline complex complex::operator +(const complex &c) { return complex(real+c.real,imag+c.imag); }inline complex complex::operator -(const complex &c) { return complex(real-c.real,imag-c.imag); }inline complex complex::operator *(const complex &c) { return complex(real * c.real-imag * c.imag,real * c.imag+imag * c.real); }inline complex complex::operator /(const complex &c) { return complex((real * c.real + imag + c.imag)/ (c.real*c.real+c.imag*c.imag),(imag* c.real - real * c.imag)/(c.real * c.real + c.imag *c.imag)); }void print(const complex &c){ if(c.imag<0)cout<<c.real<<c.imag<<'i';elsecout<<c.real<<'+'<<c.imag<<'i';}void main( ){ complex c1(2.0,3.0),c2(4.0,-2.0),c3;c3=c1+c2;cout<<"\nc1+c2=";print(c3);c3=c1-c2;cout<<"\nc1-c2=";print(c3);c3=c1*c2;cout<<"\nc1*c2=";print(c3);c3=c1/c2;cout<<"\nc1/c2=";print(c3);c3=(c1+c2)*(c1-c2)*c2/c1;cout<<"\n(c1+c2)*(c1-c2)*c2/c1=";print(c3);cout<<endl;}该程序的运行结果为:c1+c2=6+1ic1-c2=-2+5ic1*c2=14+8ic1/c2=0.45+0.8i(c1+c2)*(c1-c2)*c2/c1=9.61538+25.2308i小结:1.在程序中,定义了4个成员函数作为运算符重载函数。
8 多态性和虚函数
注意: ① 定义为内联函数
② 形参为complex 类的常引用,目的: 保证引用的complex 对象值不变
8.2 运算符重载
友元函数
8.2 运算符重载
c1.real=2.0 c1.imag=3.0 c2.real=4.0c2.imag=-2.0 c3.real=0 c3.imag=0
8.2 运算符重载
8.2 运算符重载
运算符重载
• 为什么要进行运算符重载: 使原有的运算符能够用于用户自定义类 例:class complex; //用户自定义一个复数类 { …}; complex com1,com2; //定义两个复数 com1+com2 ? com1-com2 ? ……
8.2 运算符重载
运算符重载
8.1 函数重载
– 字符串可调用的操作函数(即string类的成员函 数)(共23个函数):
assign( ) //为字符串赋新值 swap( ) //交换两个字符串的内容 append( ) //在字符串尾部添加字符 insert( ) //插入字符 erase( ) //删除字符 clear( ) //删除全部字符 compare( ) //比较字符串 size( ),length( ) //返回字符数量 empty( ) //判断字符串是否为空 …… //其它操作请见C++类库文档
②
8.2 运算符重载
c1.real=2.0 c1.imag=3.0 c2.real=4.0c2.imag=-2.0 c3.real=14.0c3.imag=8.0 c3.real=-2.0c3.imag=5.0 c3.real=0.1 c3.imag=0.8 c3.real=6.0 c3.imag=1.0 c3.real=0 c3.imag=0
多态性与虚函数.doc
多态性与虚函数多态性的概念多态性(polymorphism)是面向对象程序设计的一个重要特征。
利用多态性可以设计和实现一个易于扩展的系统。
有过非面向对彖语言开发经历的人,通常对这一章节的内容会觉得不习惯,因为很多人错误地认为,支持类的封装的语言就是支持血向对象的,其实不然,Visual BASIC 6.0是典型的非面向对象的开发语言,但是它的确是支持类,支持类并不能说明就是支持面向对象,能够解决多态问题的语言,才是真正支持面向对象的开发的语言,所以务必提醒有过其它非面向对象语言基础的读者注意!多态的意思是指具有不同功能的函数可以用同一个函数名,这样就可以用一个函数名调用不同内容的函数。
其实,我们己经接触过多态性的现象,例如函数的重载、运算符重载都是多态现象。
只是那时没有用到多态性这一专业术语而已。
例如,使用运算符”+”使两个数值相加,就是发送一个消息,它要调用operator+函数。
实际上,整型、单精度型、双精度型的加法操作过程是互不相同的,是由不同内容的函数实现的。
显然,它们以不同的行为或方法來响应同一消息。
在面向对象方法中一般是这样表述多态性的:向不同的对象发送同一个消息,不同的对象在接收时会产生不同的行为(即方法)。
也就是说,每个对象可以用自己的方式去响应共同的消息。
从系统实现的角度看,多态性分为两类:静态多态性和动态多态性。
以前学过的函数重载和运算符重载实现的多态性属于静态多态性,在程序编译时系统就能决定调用的是哪个函数,因此静态多态性乂称编译时的多态性。
静态多态性是通过函数的重载实现的(运算符重载实质上也是函数重载)。
动态多态性是在程序运行过稈中才动态地确泄操作所针对的对彖。
它又称运行时的多态性。
动态多态性是通过虎函数(virtual function)实现的。
本章中主要介绍动态多态性和虚函数。
要研究的问题是:当一个基类被继承为不同的派生类时,各派生类可以使用与基类成员相同的成员名,如果在运行时用同一个成员名调用类对象的成员,会调用哪个对象的成员?也就是说,通过继承而产生了相关的不同的派生类,与基类成员同名的成员在不同的派生类中有不同的含义。
多态性和虚函数设计
for(vector<Shape*>::iterator it=va.begin(); it!=va.end(); ++it)
(*it)->Display();
system("pause");
}
【实验结果】
【教师评语和成绩】
成绩:指导教师:日期:
输入文件shape.txt如下:
C 123 5 10
C 6 61 20
R 6 8 8 10
C 2 3 1
X
若第一个字符为'C',则后面为圆的数据
若第一个字符为'R',则后面为长方形的数据
若第一个字符为'X',表示输入结束
int main(){
vector<Shape*> va;
ifstream in("shape.txt");
Shape *ps;
char s;
double a,b,c,d,e,f;
for(;in>>s && s!='X' ;){
if(s=='C'){in>>a>>b>>c;ps=new Circle(a,b,c); va.push_back(ps);}
else if(s=='R'){
in>>a>>b>>c>>d;
姓名:
专业:
班级:
学号:
科目:
实验日期:
实验题目:多态性和虚函数设计
【实验目的】
1.在掌握继承与派生关系的基础上,进一步理解虚函数与多态性的关系,实现运行时的多态性。
多态性与虚函数实验报告
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.支持动态绑定:通过运行时的动态绑定,可以根据对象的实际类型来确定调用的函数,实现了动态绑定和多态性。
c++多态性与虚函数习题答案
多态性与虚函数1.概念填空题1.1 C++支持两种多态性,分别是编译时和运行时。
1.2在编译时就确定的函数调用称为静态联编,它通过使用函数重载,模板等实现。
1.3在运行时才确定的函数调用称为动态联编,它通过虚函数来实现。
1.4虚函数的声明方法是在函数原型前加上关键字virtual。
在基类中含有虚函数,在派生类中的函数没有显式写出virtual关键字,系统依据以下规则判断派生类的这个函数是否是虚函数:该函数是否和基类的虚函数同名;是否与基类的虚函数参数个数相同、类型;是否与基类的虚函数相同返回类型。
如果满足上述3个条件,派生类的函数就是虚函数。
并且该函数覆盖基类的虚函数。
1.5 纯虚函数是一种特别的虚函数,它没有函数的函数体部分,也没有为函数的功能提供实现的代码,它的实现版本必须由派生类给出,因此纯虚函数不能是友元函数。
拥有纯虚函数的类就是抽象类类,这种类不能实例化。
如果纯虚函数没有被重载,则派生类将继承此纯虚函数,即该派生类也是抽象。
3.选择题3.1在C++中,要实现动态联编,必须使用(D)调用虚函数。
A.类名B.派生类指针C.对象名D.基类指针3.2下列函数中,不能说明为虚函数的是(C)。
A.私有成员函数B.公有成员函数C.构造函数D.析构函数3.3在派生类中,重载一个虚函数时,要求函数名、参数的个数、参数的类型、参数的顺序和函数的返回值(A)。
A.相同B.不同C.相容D.部分相同3.4当一个类的某个函数被说明为virtual时,该函数在该类的所有派生类中(A)。
A.都是虚函数B.只有被重新说明时才是虚函数C.只有被重新说明为virtual时才是虚函数D.都不是虚函数3.5(C)是一个在基类中说明的虚函数,它在该基类中没有定义,但要求任何派生类都必须定义自己的版本。
A.虚析构函数B.虚构造函数C.纯虚函数D.静态成员函数3.6 以下基类中的成员函数,哪个表示纯虚函数(C)。
A.virtual void vf(int);B.void vf(int)=0;C.virtual void vf( )=0;D.virtual void vf(int){ }3.7下列描述中,(D)是抽象类的特性。
多态性和虚函数 实验报告
多态性和虚函数实验报告淮海工学院计算机科学系实验报告书课程名:《 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 class Point { public:Point(float=0,float=0); void setPoint(float,float); float getX() const {return x;}C++程序设计实验报告float getY() const {return y;}friend ostream & operator<protected: };Point::Point(float a,float b) {x=a;y=b;}void Point::setPoint(float a,float b) {x=a;y=b;}ostream & operator<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<protected: };Circle::Circle(float a,float b,float r):Point(a,b),radius(r){}float radius;C++程序设计实验报告void Circle::setRadius(float r) {radius=r;}float Circle::getRadius() const {return radius;}float Circle::area() const {return 3.14159*radius*radius;}ostream &operator<cout<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<r=\protected: };Cylinder::Cylinder(float a,float b,float r,floath):Circle(a,b,r),height(h){}float height;C++程序设计实验报告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<cout<<int main() {Cylinder cy1(3.5,6.4,5.2,10);cout<感谢您的阅读,祝您生活愉快。
Ch8 多态、虚函数
8.1 8.1,多态性
8.1.1 基类和派生类
派生类的概念及其相关的语言机制使我 们能表述一种层次性的关系. 派生类应看作是基类的对象. 派生类从它的基类那里继承了多种性质.
8.1.2 继承召唤多态:同化效应
对于右边的类和对象操作,则有下 列结果: UnderGraduate Graduate 但是,若执行 s = gs; 再执行s.display(),结果为: UnderGraduate 说明,gs虽然是研究生对象,但在 赋值给大学生对象操作之后, 被大学生同化了,丧失了研究 生的本性.
8.2,虚函数的定义, ,虚函数的定义, 格式, 格式,作用
8.2.1 什么是虚函数?
虚函数是指一个类中你希望重载的成员函数, 当你用一个基类指针或引用指向一个派生类 对象的时候,你调用一个虚函数,实际调用 的是派生类的版本. ——摘自MSDN
8.2.1 什么是虚函数?(续)
例如: class Employee{ string first_name, family_name; short department; //… public: Employee(const string &name, int deft); Virtual void print(); //虚函数出现了! //… };
c++实验虚函数与多态性
实验九:虚函数与多态性一.实验目的1.掌握动态联编的概念;2.掌握虚函数和纯虚函数的使用方法;3.掌握抽象类的使用。
二.实验内容设计一个计算图形面积的类库。
它的顶层是一个抽象类,并且提供相应的接口函数。
抽象基类Shape,派生出Point类、矩形Rectangle、正方形Square,Point类派生出圆形Circle。
要求:1、每个类有构造函数、析构函数,并有相应的输出语句,如:“正在构造圆形”2、能显示每个类的信息,如:输出“我是圆形”3、能计算面积、周长4、定义一个基类Shape类型的指针,实现动态多态5、动态创建一个圆形对象,赋值给基类Shape类型的指针变量,程序最后delete该指针,保证析构函数的正确调用(提示:虚析构函数)6、在主函数测试。
三.实验操作步骤1.输入源程序,编译、连接直到没有错误2.根据实验步骤,撰写实验报告四、实验要求1.复习教材中和实验相关的内容,提前编好程序。
2.整理上机结果,完成实验报告。
3.注意总结上机体会。
C++程序设计及实训198 #include <iostream>using namespace std;#include<string>class Shape{public:virtual float area()=0;virtual float longth()=0;virtual void show()=0;virtual ~Shape(){}};class Point:public Shape{protected:int x;int y;public:Point(int a=0,int b=0){x=a;y=b;cout<<"is constructing Point"<<endl;}void show(){cout<<"I am point"<<endl;}~Point(){cout<<"is destructing Point"<<endl;}float area(){return 0;}float longth(){实训2:简单C++程序设计return 0;}};class Rectangle:public Point{protected:int l;int w;public:Rectangle(int a=1,int b=1){l=a;w=b;cout<<"is constructing Rectangle"<<endl;}void show(){cout<<"I am Rectangle"<<endl;}float area(){return l*w;}float longth(){return 2*(l+w);}~Rectangle(){cout<<"is destructing Rectangle"<<endl;}};class Square:public Shape{protected:int r;public:Square(int a=1)199C++程序设计及实训200{r=a;cout<<"is constructing Square"<<endl;}void show(){cout<<"I am Square"<<endl;}float area(){return r*r;}float longth(){return 4*r;}~Square(){cout<<"is destructing Square"<<endl;}};class Circle:public Point{protected:int r;public:Circle(int a=1){r=a;cout<<"is constructing Circle"<<endl;}void show(){cout<<"I am Circle"<<endl;}float area(){return r*r*3.14;实训2:简单C++程序设计}float longth(){return 2*3.14*r;}~Circle(){cout<<"is destructing Circle"<<endl;}};int main(){Point a(1,1);Square b(2);Rectangle c(2,1);Shape *p=new Circle ;p->show();delete p;return 0;}{201。
多态性和虚函数(精)
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. 联编的概念
虚函数与多态性
!=
<=
>=
&& ||
++
--
->* ‘
->
[]
()
new delete new[] delete[]
不能重载的算符
.
::
.*
?:
sizeof
8.1 运算符重载
8.1.1 重载运算符的限制
重载运算符函数可以对运算符作出新的解释,但原有基本语义不变: 不改变运算符的优先级 不改变运算符的结合性 不改变运算符所需要的操作数 不能创建新的运算符
第8章 虚函数与多态性
8.0 函数重载 8.1 运算符重载 8.2 类指针的关系 8.3 虚函数与动态联编 8.4 纯虚函数与抽象类 8.5 虚函数和多态性的应用 小结
多态性(Polymorphism)是指一个名字,多种语义;或界面 相同,多种实现。
重载函数是多态性的一种简单形式。 虚函数允许函数调用与函数体的联系在运行时才进行,称为
8.0 函数重载
重载示例:
参数个数相同 参数类型不同
# include <iostream.h> int abs ( int a ) ; double abs ( double f ) ; void main () { cout << abs ( -5 ) << endl ;
cout << abs ( -7.8 ) << endl ; } int abs ( int a ) { return a < 0 ? -a : a ; } double abs ( double f ) { return f < 0 ? -f : f ; }
8.3 多态性与虚函数
例:使用虚函数 #include<iostream.h> const double PI=3.14159; class point{ double x, y; public: point(float i=0, float j=0) { x=i; y=j; } virtual double area( ) { return 0.0;} }; class circle:public point { double radius; public: circle(double r=0) { radius=r; } double area( ) { return PI*radius*radius; } };
结果分析: point *pp; pp=&c; cout<<"now the area is: "<<pp->area( )<<endl; this指针是指向当前对象的指针,在point类中area( ) 可用this指针改写为如下等同形式: double area( ){return this->x * this->y;} 在执行pp->area( )时,由于此时指针pp是基类point的 指针,this指针是指向基类的,所以pp->area( )实际调用 的是基类的成员函数area( ),而不是派生类中的成员函数 area( );
可以把纯虚函数归结为:抽象类的唯一用途是为派生类提 供基类,纯虚函数的作用是作为派生类中的成员函数的基础, 并实现动态多态性。
#include<iostream.h> class A{ protected: int x; public: A( ){x=1000;} virtual void print( ) = 0; }; class B:public A{ int y; public: B( ){y=2000;} void print( ){cout<<"y="<<y<<endl;} };
翟C++第08章 多态性和虚函数
}
void fun(B0 *ptr) //普通函数 { ptr -> display ( ); } void main ( ) { B0 b0, *p; //声明基类对象和指针 B1 b1; //声明派生类对象 D1 d1; //声明派生类对象 p=&b0; fun(p); //调用基类B0函数成员 p=&b1; fun(p); //调用派生类B1函数成员 p=&d1; fun(p); //调用派生类D1函数成员
class Square:public base { public: void disp() { cout<< "x="<< x <<":"; cout<< "x square="<< x*x << endl; } }; class Cube:public base {public: void disp() { cout<< “x=”<< x <<“:”; cout<< "x cube="<< x*x*x << endl; } };
#include <iostream.h> class B0 {public: void display ( ) {cout<<"B0::display ( ) "<<endl;} }; class B1: public B0 { public: void display( ) { cout<<"B1::display ( ) "<<endl; }; class D1: public B1 { public: void display ( ) { cout<<"D1::display ( ) "<<endl; } };
多态性与虚函数
1.2.2 运算符重载
运算符重载原理
运算符重载是对已有运算符赋予多重含义,这在 程序设计过程中是十分重要与必要的。在C++语言中, 预先定义的运算符其运算对象只能是基本数据类型, 而不能用于用户定义的类型,如类实例。而在程序 设计中,为了使得程序编写更加简洁,用户希望能 使用运算符来操作类实例,因此产生了运算符重载 模式。运算符重载的过程是将特定的运算表达式转 换为对实现运算符功能的函数调用,而运算对象则 转换为运算符函数的参数。
虚函数可以在派生出的子类中有多个不同实现是虚函
数的重要特性,也就是通过这个特性,用户可以实现多 态性。由此,可以得知,虚函数都是在父类中进行声明 或定义的,而用户声明或定义虚函数的目的就是不确定 该成员函数在派生出的子类中的行为。
1.3.2 虚函数都定义和使用
可以使用如下方式来声明或定义一个虚函数。 virtual 函数类型 函数名称(参数表); 或者 virtual 函数类型 函数名称(参数表) {
指针变量→成员函数名称(参数表); 或
指针变量→成员数据名称; 最后,当类实例使用完毕后,用户使用delete操作,可以将类 实例清除,并归还对应的系统空间,其语法格式如下。
delete 类指针名称;
1.3.3 虚析构函数
指针与虚析构函数
在C++语言的继承模式下,用户可以使用指针来访问派生类,通常情况下 可以有两种方式:利用指向派生类的指针来访问与利用指向父类的指针 来访问。在这两种方式下,析构函数的作用是不同的。
1.3.3 虚析构函数
利用指针访问类实例
在C++语言中,用户可以使用指针或引用的方式来访问类实例。 其具体方式如下:
类名称 *指针名称 = new 类名称; 当类指针定义完毕后,指针指向的类实例中的构造函数将自动 执行,如果用户需要访问该实例中的成员函数或者访问该实例中 的成员数据,可以使用下面的方式:
第8章虚函数与多态性
2 虚函数
• 函数调用绑定 • 虚函数 • 虚函数的相关规则 • 实现多态性的步骤 • 动态绑定的实现
virtual void salary(){ } //基类中声明的虚函数 }; //下面的派生类中重写salary()都是虚函数
3 抽象类
class manager : public employee{
代码中类层次如下图所示
1 向上类型转换 2 虚函数 3 抽象类 4 RTTI 5 类层次设计的例子 6 小结
employeeCtrl payroll()
manager salary()
employee salary()
向上类型转换
programmer salary()
parttime salary()
void salary(){ /*程序员工资的计算和发放*/
} };
3 抽象类
class parttime : public employee{
4 RTTI
public: void salary(){
5 类层次设计的例子
/*兼职人员工资的计算和发放*/
6 小结
}
};
上面的代码可以修改为如下形式
1 向上类型转换
派生类向上转换为基类类型,这在逻辑上是 合理的,在物理上也是安全的。
▪ 在逻辑上方面,派生类继承基类的公共接口,能 够发送给基类对象的消息也能够发送给派生类对 象。派生类是特殊的基类类型,派生类对象(或 地址)可以作为基类的实例(或地址),替代基 类对象(或地址)使用。
▪ 在物理方面,基类的成员被派生类继承,在派生 类对象中封装着一个无名的基类子对象,派生类 对象的存储空间中从首地址开始存放的的这个基 类子对象。因此,进行向上类型转换时,通过派 生类对象切片,能够提供足够的基类信息,得到 基类对象。而使用基类指针(或引用)指向派生 类对象时也不会破坏指针(或引用)的指向规则。
多态和虚函数
多态和虚函数
多态和虚函数是面向对象编程中非常重要的概念。
多态是指同一种操作作用于不同的对象上面,可以产生不同的执行结果。
而虚函数则是实现多态的一种方式。
在面向对象编程中,我们经常会遇到需要对不同的对象进行相同的操作的情况。
例如,我们可能需要对不同的动物进行喂食,但是不同的动物需要不同的食物。
这时候,我们就可以使用多态来实现这个功能。
我们可以定义一个抽象的动物类,然后让不同的动物类继承这个抽象类,并实现自己的喂食方法。
然后我们就可以通过调用这个抽象类的喂食方法来喂食不同的动物,而不需要知道具体是哪种动物。
虚函数是实现多态的一种方式。
虚函数是在基类中定义的一种特殊的函数,它可以被子类重写。
当我们通过基类指针或引用调用虚函数时,实际上会调用子类中重写的虚函数。
这样就可以实现多态,让不同的子类实现自己的方法,而不需要知道具体是哪种子类。
虚函数的实现是通过虚函数表来实现的。
每个对象都有一个指向虚函数表的指针,虚函数表中存储了虚函数的地址。
当我们调用虚函数时,实际上是通过对象的指针或引用找到虚函数表,然后根据虚函数的索引找到对应的虚函数地址,最终调用虚函数。
多态和虚函数是面向对象编程中非常重要的概念。
通过使用多态和
虚函数,我们可以实现代码的复用和扩展性,让代码更加灵活和易于维护。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
cout<<"正方形面积S*S="<<a[2]->Area()<<endl;
cout<<"圆面积="<<a[3]->Area()<<endl;
for(int i=0;i<4;i++)
{
a[i]->Setdata(n,m);
sum+=a[i]->Area();
};
class Triangle1:public Shape
{
float W,H;
public:
Triangle1(float w=0,float h=0){ W=w; H = h; }
float Area( void){ return W*H/2; }
void Setdata(float w,float h=0){ W=w; H = h; }
};
class Triangle2:public Shape
{
float S,H;
public:
Triangle2(float s=0){S=s; }
float Area( void){ return S*S; }
void Setdata(float s,float h) { S=s,H=h; }
};
};
1.3如果将Vehicle类的定义修改为纯虚函数,找出main()函数中将使编译出错的行删除(或改为注释),请写出程序的执行结果,并在上机时对照理解
class Vehicle
{public:
virtual void run() const = 0; //(3) run()为纯虚函数
};
1.4用自己的话概括你对虚函数、多态性和抽象类的理解。
源程序:
#include<iostream>
using namespace std;
class Shape
{
public:
virtual float Area( void) =0;//求面积
virtual void Setdata(float ,float=0) =0;//设置图形数据
};
class Triangle:public Shape
};
class Car: public Vehicle
{public:
void run() const {cout << "run a car. "<<endl; }
};
class Airplane: public Vehicle
{public:
void run() const {cout << "run a airplane. "<<endl;}
};
int main()
{
Triangle t(4,6);
Triangle1 t1(3,8);
Triangle2 t2(6);
Triangle3 t3(8);
float sum=0;
Shape *a[4]={&t,&t1,&t2,&t3};
float n=5,m=9;
cin>>n>>m;
cout<<"三角形面积W* H/2="<<a[0]->Area()<<endl;
class Triangle3:public Shape
{
float R,A;
public:
Triangle3(float r=0){ R=r; }
float Area(void){ return R*R*3.14; }
void Setdata(float r,float a){ R=r,A=a;}
把这个基类派生出其它几何图形类。如派生出的三角形类为:
class Triangle:public Shape
{
float W,H;//三角形边长为W,高为H
public:
Triangle(float w=0,float h=0){ W=w; H = h; }
float Area( void){ return W*H/2; }
解:
计算这四种几何图的面积公式分别是:
a[i]->Area()的边长为W,高为H时,则三角形的面积为W* H/2;
矩形的边长为W,宽为H时,则其面积为W* H;
正方形的边长为S,则正方形的面积为S*S;
圆的半径为R,其面积为3.1415926 *R *R。
为设置几何图形的数据并求出几何图形的面积,需要定义一个包含两个虚函数的类:
实验
一、实验目的和要求
1.了解多态的概念;
2.了解虚函数的作用及使用方法;
3.了解静态关联和动态关联的概念和用法;
4.了解纯虚函数和抽象类的概念和用法
二、实验内容和
1.阅读下面的程序
1.1请写出程序的执行结果,并在上机时对照理解
class Vehicle
{public:
void run() const { cout << "run a vehicle. "<<endl; } //(1) run()为虚函数
};
int main()
{ cout<<"(a)直接用对象访问成员函数: "<<endl;
Vehicle v;
v.run();
Car car;
Airplane airplane;
car.run();
airplane.run();
cout<<"(b)用指向基类的指针访问成员函数: "<<endl;
Vehicle *vp;
}
cout<<"所有几何图形面积之和"<<sum<<endl;
return 0;
}
结果:
{
float W,H;//三角形边长为W,高为H
public:
Triangle(float w=0,float h=0){ W=w; H = h; }
float Area( void){ return W*H/2; }
void Setdata(float w,float h=0){ W=w; H = h; }
虚函数:就是在基类声明函数是虚拟的,并不是实际存在的函数,允许在派生类中重新定义与基类同名的函数.
多态性:同一类族中不同类的对象,对同一函数调用做出不同的响应。
抽象类:不用来定义对象而只作为一种基本类型用作继承的类;为一个类族提供一个公共接口。
2.利用虚函数实现的多态性来求四种几何图形的面积之和。
这四种几何图形是:三角形、矩形、正方形和圆。几何图形的类型可以通过构造函数或通过成员函数来设置。
vp=&car;
vp‐>run();
vp=&airplane;
vp‐>run();
}
Hale Waihona Puke 1.2如果将Vehicle类的定义修改为虚函数,其余不变,请写出程序的执行结果,并在上机时对照理解
class Vehicle
{public:
virtual void run() const { cout << "run a vehicle. "<<endl; } //(2) run()为虚函数
class Shape
{
public:
virtual float Area( void) =0;//求面积
virtual void Setdata(float ,float =0) =0;//设置图形数据
};
因面积的计算依赖于几何图形,故在类中只能定义一个纯虚函数Area。同理,设置几何图形数据的函数Setdata也只能定义为虚函数。
void Setdata(float w,float h=0){ W=w; H = h; }
};
在派生类中定义了基类中两个虚函数的实现。为了实现求面积和设置数据的多态性,必须定义一个类,该类中定义一个指向基类Shape的指针数组,其元素分别指向由基类Shape派生出的不同的几何图形类,并完成求出所有几何图形面积之和,以及设置参数的函数。