第6章 多态性与虚函数

合集下载

虚函数与多态性实验

虚函数与多态性实验

一.实验目的及要求1.进一步熟悉类的设计、运用继承与派生机制设计派生类,合理设置数据成员和成员函数。

2.掌握通过继承、虚函数、基类的指针或引用实现动态多态性的方法。

3.理解并掌握具有纯虚函数的抽象类的作用,在各派生类中重新定义各纯虚函数的方法,以及此时实现的动态多态性。

二.实验内容在自己的文件夹下建立一个名为exp5的工程,在该工程中做如下操作:定义一个抽象类容器类,其中定义了若干纯虚函数,实现求表面积、体积、输出等功能。

由此抽象类派生出正方体、球体和圆柱体等多个派生类,根据需要定义自己的成员变量,在各个派生类中重新定义各纯虚函数,实现各自类中相应功能,各个类成员的初始化均由本类构造函数实现。

(1)在主函数中,定义容器类的指针和各个派生类的对象,使指针指向不同对象处调用相同的函数能执行不同的函数代码,从而实现动态多态性。

(2)定义一个顶层函数void TopPrint(Container &r);使得主函数中调用该函数时,根据实在参数所有的类自动调用对应类的输出函数。

(3)主函数中定义一个Container类对象,观察编译时的错误信息,从而得出什么结论三.实验程序及运行结果#include <iostream>using namespace std;class Base{public:virtual void f(){ cout << "调用Base::f()" << endl; }};class Derived: public Base{public:void f(){ cout << "调用Derived::f()" << endl; } // 虚函数};int main(void){Derived obj; // 定义派生类对象Base *p = &obj; // 基类指针p->f(); // 调用函数f()system("PAUSE");return 0;}2.#include <iostream>using namespace std; //class Base{public:virtual void Show() const{ cout << "调用Base::Show()" << endl; } // 虚函数};class Derived: public Base{public:void Show() const{ cout << "调用Derived::Show()" << endl; }};void Refers(const Base &obj) // 基类引用{obj.Show(); // 调用函数Show()}int main(void){Base obj1;Derived obj2; // 定义对象Refers(obj1); // 调用函数Refers()Refers(obj2);system("PAUSE");return 0;}3.#include <iostream>using namespace std; /class Base{private:int m;public:Base(int a): m(a){ }virtual void Show() const{ cout << m << endl; }// 虚函数};class Derived: public Base{private:int n;public:Derived(int a, int b): Base(a), n(a){ } // 构造函数void Show() const{cout << n << ","; /Base::Show(); // 调用基类的Show() }};int main(void){Base obj1(168);Derived obj2(158, 98);Base *p;p = &obj1;p->Show();p = &obj2;p->Show();p->Base::Show();system("PAUSE");return 0;}4.#include <iostream>using namespace std;class A{public:virtual void Show() const{ cout << "基类A" << endl; } };class B: public A{public:void Show() const{ cout << "派生类B" << endl; } };int main(void){B obj;A *p = &obj;p->Show();system("PAUSE");return 0;}5.#include <iostream>using namespace std;const double PI = 3.1415926;class Shape{public:virtual void Show() const = 0;static double sum;};class Circle: public Shape{private:double radius;public:Circle(double r): radius(r){ sum += PI * radius * radius; }void Show() const{cout << "圆形:" << endl;cout << "半径:" << radius << endl;cout << "面积:" << PI * radius * radius << endl;}};class Rectangle: public Shape{private:double height;double width;public:Rectangle(double h, double w): height(h), width(w){ sum += height * width; }void Show() const{cout << "矩形:" << endl;cout << "高:" << height << endl;cout << "宽:" << width << endl;cout << "面积:" << height * width << endl;}};double Shape::sum = 0;int main(void){char flag = 'Y'; 'Shape *p;while (toupper(flag) == 'Y'){cout << "请选择输入类别(1.圆形2.矩形)";int select;cin >> select;switch (select){case 1:double r;cout << "输入半径:";cin >> r;p = new Circle(r);p->Show();delete p;break;case 2:double h, w;cout << "输入高:";cin >> h;cout << "输入宽:";cin >> w;p = new Rectangle(h, w);p->Show(); // 显示相关信息delete p; // 释放存储空间break;default: // 其它情况, 表示选择有误cout << "选择有误!"<< endl;break;}cout << endl << "是否继续录入信息?(Y/N)";cin >> flag;}cout << "总面积:" << Shape::sum << endl;system("PAUSE");return 0;}6.#include <iostream>using namespace std;const double PI = 3.1415926;const int NUM = 10;class Shape{public:virtual void ShowArea() const = 0;static double sum;};class Circle: public Shape{private:double radius;public:Circle(double r): radius(r){ sum += PI * radius * radius; }void ShowArea() const{ cout << "圆面积:" << PI * radius * radius << endl; }};class Rectangle: public Shape{private:double height;double width;public:Rectangle(double h, double w): height(h), width(w){ sum += height * width; }void ShowArea() const{ cout << "矩形面积:" << height * width << endl; }};class Square: public Shape{private:double length;public:Square(double a): length(a){ sum += length * length; }void ShowArea() const{ cout << "正方形面积:" <<length * length << endl; } };double Shape::sum = 0;int main(void){Shape *shape[NUM];int count = 0;while (count < NUM){cout << "请选择(1.圆形2.矩形3.正方形4.退出):";int select;cin >> select;if (select == 4) break;switch (select){case 1:double r;cout << "输入半径:";cin >> r;shape[count] = new Circle(r);shape[count]->ShowArea();count++;break;case 2:double h, w;cout << "输入高:";cin >> h;cout << "输入宽:";cin >> w;shape[count] = new Rectangle(h, w);shape[count]->ShowArea();count++;break;case 3:double a;cout << "输入边长:";cin >> a;shape[count] = new Square(a);shape[count]->ShowArea();count++;break;default:cout << "选择有误!"<< endl;break;}}cout << "总面积:" << Shape::sum << endl;for (int i = 0; i < count; i++) delete shape[i];system("PAUSE");return 0;}五.实验总结通过本次试验 我更深刻的理解了某些语句如何使用及结构体的优点 也能更加熟练的编写简单的程序了 我深知实践要比书本更加重要 今后还要多练习 在实践中学习。

虚函数的多态性机制分析

虚函数的多态性机制分析
I N 0 9 3 4 SS 1 0 - 0 4
E ma : s @c c .e C — i xj c c t n l l n .
ht /www. z .e .n t / p: dn sn tc
C m u r n we g n e h o g o p t o l ea dT c n l y电脑 知 识 与技术 eK d o

1面 向对 象 程 序 设 计 的 多 态 性
在C+ , + 中 把类 看 作 类 型 , 以 p bi 式 继 承 的派 生 类 看 作是 基 类 的 子类 型 。从 而 产生 了多 态 对象 的类 型 不但 可 以是 派生 类 , ) 也可 以是 基类 , 也就是 说 , 个对 象 可 以 属 于 多种 类 型 。 一 2 基 类 的指 针 可 以 指 向基 类 对 象 , 可 以 指 向派 , 类 对象 ; ) 也 } - 基类 的 引用 可 以引 用 基 类 对 象 , 可 以引 用 派 生类 对 象 即一 个 对 也
象标 识 符 可 以属 于 多 种类 型 , 可 以标 识 多种 对 象 它
3 一 个 消息 可 以发 送 到 基 类 对象 , 可 以发 送 到 派 生类 刘 象 , 而 可 能 会得 到 不 同 的 解 释 , ) 也 从 引起 不 同的 动作 , 产生 不 同的 效果
C + 以 支持 两 种 多 态性 : +可 静态 多 态 性 和动 态 多 态 性 我们 知 道 , 序 在 运 行 前 的编 译 连 接 阶段 会 根据 源 程 序 中的 要 调 用 的 函 程
Abtat I jc— i ne rga migtelhfac eettig o r ci l hn me o el r . th oy rh s c: nOb t Or tdPorm n , n et erfc n s f ea hc e o n ni r l b e P l r e e h in l sh h r a p n a wo d u t mop —

c#第6章 继承与多态性

c#第6章 继承与多态性

例如: 例如: class Humen { public string name; name; public string sex; sex; public string work ; } class Teacher:Humen Teacher: { public string speciality ; public string department; department; } Human是基类 Teacher是派生类 Human是基类,Teacher是派生类,它拥有基类 是基类, 是派生类, 的全部成员。 的全部成员。
派生类隐藏基类成员 :用new关键字。 new关键字 关键字。 隐藏基类的字段成员: 隐藏基类的字段成员: 派生类可以声明与基类有相同的名称和类型的字 派生类可以声明与基类有相同的名称和类型的字 段成员来隐藏基类的字段。 来隐藏基类的字段 段成员来隐藏基类的字段。这时通过派生类引用 或对象访问的是派生类的字段, 或对象访问的是派生类的字段,基类的相应成员 被屏蔽了。但是通过指向派生类对象的基类引用 被屏蔽了。但是通过指向派生类对象的基类引用 访问的则是基类的字段。 访问的则是基类的字段。 隐藏基类的方法成员: 隐藏基类的方法成员: 派生类可以声明与基类有相同的方法名称和形参 表的方法成员来隐藏基类的方法 基类的方法, 表的方法成员来隐藏基类的方法,与返回类型无 这时通过派生类引用或对象访问的是派生类 关。这时通过派生类引用或对象访问的是派生类 的方法成员,基类的相应方法成员被屏蔽了。 的方法成员,基类的相应方法成员被屏蔽了。但 是通过指向派生类对象的基类引用访问的则是基 指向派生类对象的基类引用访问的则是 是通过指向派生类对象的基类引用访问的则是基 类的成员。 类的成员。 派生类中可以通过 可以通过base关键字访问被隐藏的基 在派生类中可以通过base关键字访问被隐藏的基 类成员。 类成员。 详见例MaskBase。 详见例MaskBase。

【C++面向对象的程序设计】6多态性

 【C++面向对象的程序设计】6多态性

虚析构函数
析构函数的作用是对象撤销之后清理现场。 在派生类对象撤销时,一般先调用派生类的 析构函数。再调用基类的析构函数。
然而,当定义的是一个指向基类的指针变量, 使用new运算符建立临时对象时,如果基类 中有析构函数,则在使用delete析构时只会 调用基类的析构函数。
这就需要将基类中的析构函数声明为虚函数。
虚函数的声明与使用
声明虚函数的一般格式如下: virtual 函数原型;
⑴ 必须首先在基类中声明虚函数。 ⑵ 派生类中与基类虚函数原型完全相同的成员函 数,即使在说明时前面没有冠以关键字virtual也 自动成为虚函数。
声明虚函数
⑶ 只有非静态成员函数可以声明为虚函数。 ⑷ 不允许在派生类中定义与基类虚函数名字及参数 特征都相同,仅仅返回类型不同的成员函数。 编译时 出错。 ⑸ 系统把函数名相同但参数特征不同的函数视为不 同的函数。 ⑹ 通过声明虚函数来使用C++提供的多态性机制时, 派生类应该从它的基类公有派生。
构函数等内容。
本章内容
静态联编与动态联编 虚函数的声明与使用 纯虚函数和抽象类 虚析构函数
Hale Waihona Puke 静态联编与动态联编所谓联编(tinding),就是使一个计算机程序的不同部 分彼此关联的过程。
静态联编在编译阶段完成,因为所有联编过程都在程 序开始运行之前完成,因此静态联编也叫先前联编或早期 联编。
另一种情况编译程序在编译时并不确切知道应把发送 到对象的消息和实现消息的哪段具体代码联编在一起,而 是在运行时才能把函数调用与函数体联系在一起,则称为 动态联编。
动态联编的实现
C ++语言中的动态联编是通过使用虚函数表 (Virtual Function Table)来实现的,虚函数表也称 为v-表。

实验四 虚函数与多态性

实验四 虚函数与多态性

实验四虚函数与多态性实验目的和要求 :1 了解多态性在 C++ 中的体现。

2 掌握虚函数的应用。

3 了解抽象类。

实验内容:定义一个基类为哺乳动物类Mammal,其中有数据成员年龄、重量、品种,有成员函数move()、speak()等,以此表示动物的行为。

由这个基类派生出狗、猫、马、猪等哺乳动物,它们有各自的行为。

编程分别使各个动物表现出不同的行为。

要求如下:1、从基类分别派生出各种动物类,通过虚函数实现不同动物表现出的不同行为。

2、今有狗: CAIRN:3岁,3kg;DORE:4岁,2kg;猫: CAT:5 岁,4kg;马: HORSE,5岁,60kg;猪: PIG,2岁,45kg。

3、设置一个 Mammal 类数组,设计一个屏幕菜单,选择不同的动物或不同的品种,则显示出动物相对应的动作,直到选择结束。

4、对应的动作中要先显示出动物的名称,然后显示年龄、重量、品种、叫声及其他特征。

实验原理:1.多态性:多态是指同样的消息被不同类型的对象接受时导致不同的行为,所谓消息是指对类的成员函数的调用,而不同的行为是指不同的实现,也就是调用不同的函数。

多态性从实现的角度来讲可以划分为两类:编译时的多态性和运行时的多态性。

编译时的多态性是在编译的过程中确定同名操作的具体操作对象,也就是通过重载函数来实现的。

运行时的的多态性是在程序运行过程中才动态地确定操作所针对的具体对象,使用虚函数来实现的。

2.虚函数:虚函数是重载的另一种形式,它提供了一种更为灵活的多态性机制。

虚函数允许函数调用与函数体之间的联系在运行时才建立,也就是运行时才决定如何动作,即所谓的“动态连接”。

虚函数成员的定义:virtual 函数类型函数名(形参表)3.(1)抽象类:抽象类是一种特殊的类。

抽象类是为了抽象和设计的目的而建立的。

一个抽象类自身无法实例化,也就是说无法定义一个抽象类的对象,只能通过继承机制,生成抽象类的非抽象派生类,然后再实例化。

多态性与虚函数实验报告

多态性与虚函数实验报告

多态性与虚函数实验报告实验目的:通过实验掌握多态性和虚函数的概念及使用方法,理解多态性实现原理和虚函数的应用场景。

实验原理: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++多态性与虚函数习题答案

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)是抽象类的特性。

面向对象程序设计教案

面向对象程序设计教案
派生类的构造函数和析构函数




理解类的继承的概念,能够定义和使用类的继承关系
掌握派生类的声明与定义方法
熟悉三种派生方式的访问特性
教学
方法

教学
手段
讲授法
多媒体课件




第5章继承与派生类
5.1继承与派生类
(一)为什么要使用继承
(二)派生类的声明




(三)基类成员在派生类中的属性
(四)派生类对基类成员的访问规则
多媒体课件




6.3纯虚函数和抽象类
(一)纯虚函数
(二)抽象类
6.4程序举例
6.5本章小结
课后
作业
P208 6-11
实验七:多态性与虚函数
教学
后记
课时计划(教案)
编号11
周次
日期
月日
课时安排
2
课题
运算符重载(一)
教材的重点、
难点分析
友元运算符函数
成员运算符函数




理解运算符重载的概念和使用方法
(四)单目运算符“++”和“- -”的重载
(五)赋值运算符“=”的重载
(六)下标运算符的重载
7.4类型转换
7.5本章小结
课后
作业
P244 3-7
实验八:运算符重载
教学
后记
课时计划(教案)
编号13
周次
日期
月日
课时安排
2
课题
模板
教材的重点、
难点分析
函数模板

试谈C++的多态性和虚函数

试谈C++的多态性和虚函数

动。按照联编所进行的阶段不同 , 可分为静态联编
和动态联编。静态联编是指在程序编译阶段进行
的联编 , 这种联编过程是在程序运行之前完成 的,
又称为早期联编。动态联编是指联编要在程序运 行时动态地进行 , 实际上是在运行时虚函数的实
{ul : pbc i
s t t d ( t ,i ) t ci d i n Y a na n x t i
1 1编译 时的 多 态性 .
它和封装性 、 继承性构成 了面向对象程序设计的三 大特性 。多态性是指 当不 同对象接受到相 同的消
法” 。多态性的重要 目标之一是实现程序中的表示 独立性, 从而提高程序的可扩展性与可复用性。
1多态性
静态联编支持的多态性称为编译时的多态性 , 也称静态多态性 , 它是通过函数重载和运算符重载
调用的是哪一个函数。 函数重载是指在相同的作用域 内, 同一个 函数
息时产生不 同的行为 , 从而实现“ 一个接 口, 多种方 实现的, 编译器对源程序进行编译时就可以确定所
名对应着多个不 同的实现。函数重载要求 : 函数的
可以是形参的类型不同, 或者两者都不相同。函数
程序 1 :
维普资讯
第8 卷第 4期
20 O6年 1 2月
黄 冈 职 业 技 术 学 院 学 报
V1 o 08 . .N 4
De .O 6 e20
试谈 C++的多态性和虚 函数
范秋 生
( 冈职 业技 术学院 黄 湖 北 黄冈 480 ) 302
摘 要: 本文分析 了C++中的两种多态性 : 编译时的多态性和运行时的多态性 , 通过 函数重裁和虚

8 - 2

第7部分 多态性与虚函数

第7部分  多态性与虚函数

例: 虚函数成员
#include <iostream> using namespace std; class B0 {public: virtual 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;} };
B0 <<virtual>>+display():void
B1 +display():void
D1 +display():void
包含虚成员函数的B0类及派生关系的UML图表示
实例讲解
#include <iostream.h> class Base { public: virtual void fun(int x){cout<<"base class, x="<<x<<endl;} }; 派生类的函数原型与基类中的函数原 class Derive:public Base 型不同(参数类型不同),所以不能 { 实现多态性。 public: void fun(float x){cout<<"derive class, x="<<x<<endl;} }; void globefun(Base &b) { int i=1; b.fun(i); float f=2.0; b.fun(f); } void main() { Base b; Derive d; globefun(b); globefun(d); }

虚函数的用法

虚函数的用法

虚函数的用法
虚函数是面向对象编程中的一个重要概念。

它允许子类重写父类中的同名函数,以实现多态性。

在C++中,使用关键字"virtual"来声明一个函数为虚函数。

虚函数的使用有以下几个关键点:
1. 多态性:虚函数的主要作用是实现多态性。

当一个指向父类的指针或引用调用一个虚函数时,实际执行的是子类中重写的函数。

这种行为允许在运行时根据对象的实际类型来确定调用的函数。

2. 动态绑定:虚函数的调用是动态绑定的,也就是说在运行时确定具体调用的函数。

与之相反的是静态绑定,它是在编译时确定调用的函数。

动态绑定使得程序具有更大的灵活性和扩展性。

3. 虚函数表:为了实现动态绑定,编译器会为每个包含虚函数的类创建一个虚函数表(vtable)。

虚函数表是一个存储函数指针的数组,每个函数指针指向对应虚函数的实际实现。

每个对象都有一个指向其类的虚函数表的指针,通过这个指针可以实现动态调用。

4. 纯虚函数:有时候父类中的虚函数并不需要有实际的实现,而只
是为了在子类中进行重写。

这种函数被称为纯虚函数,可以通过在函数声明中添加"= 0" 来表示。

包含纯虚函数的类被称为抽象类,它只能作为基类使用,不能被实例化。

综上所述,虚函数是实现多态性的关键机制之一。

通过在父类中声明虚函数并在子类中重写,可以实现基于对象实际类型的动态绑定,提高程序的灵活性和可扩展性。

总结

总结

C++
11
第六章 多态性和虚函数
三、虚函数 1.虚函数的声明格式 2.虚函数的作用 3.虚函数的使用方法
4.虚析构函数
四、纯虚函数和抽象类 1.纯虚函数:作用、声明 2.抽象类
C++ 12
C++ 7
第五章 继承和派生
一、继承和派生的基本概念及实现 1.继承的基本概念:继承、派生、继承和派生的目的 2.派生类的声明 3.类成员的访问控制——继承方式 二、多继承和单继承 1.多继承和单继承 2.多继承中派生类的声明
C++
8
第五章 继承和派生
三、派生类的构造、析构函数 1.继承中的构造函数 2.继承中的析构函数 3.同名隐藏规则
C++
5
第三章 类和对象的进一步讨论
五、友元函数和友元类 友元函数和友元类:声明、使用
C++
6
第四章 运算符重载
一、运算符重载的实质和规则 1.运算符重载的实质:运算符重载的实质、必要性、实现机制 2.运算符重载的规则和限制 二、运算符重载的两种形式 1.运算符重载为成员函数 2.运算符重载为友元函数 三、类类型转换 1. 转换构造函数作用 2.类型转换函数
3.对象指针:指向对象的指针、指向对象成员的指针(数据成 员和成员函数)
C++
4.自引用指针
4
第三章 类和对象的进一步讨论
三、共用数据的保护 1.常对象、常对象成员、常成员函数、指向对象的常指针、指 向常对象的指针变量、对象的常引用 四、静态数据成员和静态成员函数 1.静态数据成员的声明和初始化 2.静态成员函数的定义和访问
C++

虚函数继承,多态,虚继承(详细讲解)

虚函数继承,多态,虚继承(详细讲解)

虚函数的定义要遵循以下重要规则:1.如果虚函数在基类与派生类中出现,仅仅是名字相同,而形式参数不同,或者是返回类型不同,那么即使加上了virtual关键字,也是不会进行滞后联编的。

2.只有类的成员函数才能说明为虚函数,因为虚函数仅适合用与有继承关系的类对象,所以普通函数不能说明为虚函数。

3.静态成员函数不能是虚函数,因为静态成员函数的特点是不受限制于某个对象。

4.内联(inline)函数不能是虚函数,因为内联函数不能在运行中动态确定位置。

即使虚函数在类的内部定义定义,但是在编译的时候系统仍然将它看做是非内联的。

5.构造函数不能是虚函数,因为构造的时候,对象还是一片位定型的空间,只有构造完成后,对象才是具体类的实例。

6.析构函数可以是虚函数,而且通常声名为虚函数。

在编译时就能够确定哪个重载的成员函数被调用的情况被称做先期联编(earlybinding),而在系统能够在运行时,能够根据其类型确定调用哪个重载的成员函数的能力,称为多态性,或叫滞后联编(late binding)//例程3#include <iostream>usingnamespacestd;classVehicle{public:Vehicle(floatspeed,inttotal){Vehicle::speed=speed;Vehicle::total=total;}virtualvoidShowMember()//虚函数{cout<<speed<<"|"<<total<<endl;}protected:floatspeed;inttotal;};classCar:publicVehicle{public:Car(intaird,floatspeed,inttotal):Vehicle(speed,total){Car::aird=aird;}virtualvoidShowMember()//虚函数,在派生类中,由于继承的关系,这里的virtual也可以不加{cout<<speed<<"|"<<total<<"|"<<aird<<endl; }public:intaird;};voidtest(Vehicle &temp){temp.ShowMember();}intmain(){Vehicle a(120,4);Car b(180,110,4);test(a);test(b);cin.get();}运行结果:120|4110|4|180//例程2#include <iostream>usingnamespacestd;classVehicle{public:Vehicle(floatspeed,inttotal){Vehicle::speed=speed;Vehicle::total=total;}voidShowMember(){cout<<speed<<"|"<<total<<endl;}protected:floatspeed;inttotal;};classCar:publicVehicle{public:Car(intaird,floatspeed,inttotal):Vehicle(speed,total)Car::aird=aird;}voidShowMember(){cout<<speed<<"|"<<total<<"|"<<aird<<endl; }protected:intaird;};voidtest(Vehicle &temp){temp.ShowMember();}voidmain(){Vehicle a(120,4);Car b(180,110,4);test(a);test(b);cin.get();运行结果:120|4110|4虚继承是为了在多继承的时候避免引发歧义,比如类A有个就是a,B继承了A,C也继承了A,当D多继承B,C时,就会有歧义产生了,所以要使用虚拟继承避免重复拷贝。

多态性与虚函数

多态性与虚函数

第6章多态性与虚函数6.1 多态性概述6.2 重载与再定义6.3 运算符重载6.4 虚函数6.5 抽象类6.1 多态性概述6.1.1 多态的类型 6.1.2 多态的实现6.1.1 多态的类型多态性是指同一个消息被不同类型的对象接收时产生不同的行为,特点就是一个接口,多个实现。

C++中多态性按照类型可以分为强制多态、过载多态、包含多态和参数多态四种。

z强制多态是指通过语义操作,强制数据做本不属于该类型数据的操作。

编译器内部的数据的隐式转换,比如3.0+4操作时转换成3.0+4.0就属于此种类型z重载多态是指函数重载,同名的操作在不同的环境下有不同的行为。

前面学习过的普通函数重载和将要学习的类成员函数重载、运算符重载都属于此种类型。

z包含多态是指在同一类族中定义于不同类中的同名函数的多态行为。

我们本章将要学习的虚函数就属于此种类型。

z参数多态是指功能、结构实现相同但所作用于的数据类型不同,也就是数据类型参数化的多态。

第七章中的函数模板和类模板就属于此种多态。

6.1.2 多态的实现多态是指同一个消息被不同的对象接收产生不同的行为,因此,多态在实现的时候必须确定消息的操作对象。

我们根据消息和对象相结合的时间分为两种:z在程序编译连接阶段完成的,也就是说在编译的过程中确定了消息的操作对象,我们称为静态绑定。

z在程序运行阶段完成的,也就是说在程序运行的过程中才确定消息的操作对象,我们称为动态绑定。

6.2 重载与再定义6.2.1 函数的重载 6.2.2 函数的再定义6.2.1 函数的重载函数重载是指功能相似,函数名相同但所带参数不同的一组函数。

这里的“所带参数不同”既可能是参数的数据类型不同也可能是参数的个数不同。

z普通函数的重载。

int abs(int val){return val<0? –val: val;}float abs(float val){return val>0? –val: val;}6.2.1 函数的重载z类成员函数的重载。

C++继承,虚函数与多态性专题

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基类以受保护方式被继承,如果没有访问控制符则默认为私有继承。

[09_10(2)]09本④⑤班《面向对象程序设计C++》教学进度表(程细柱)

[09_10(2)]09本④⑤班《面向对象程序设计C++》教学进度表(程细柱)
实验3:类与对象(一)
实验4:类与对象(二)
实验5:继承和派生
实验6:多态性与虚函数
实验7:函数模板和类模板
实验8:输入输出的格式控制
实验9:文件的输入与输出
复习
考试
介绍面向对象程序设计的基本概念、基本特征、主要优点
使学生了解C++语言的特点、C++源程序的构成
使学生掌握类与对象的构成与定义
使学生掌握对象数组、静态成员与友元的特点与使用
使学生掌握if和switch选择结构、while和for循环结构及实现循环的方法
使学生掌握类和对象的定义及类成员的访问控制方式
使学生掌握对象数组与对象指针的定义与使用方法
使学生理解继承的含义,掌握派生类的定义方法和实现
使学生理解多态性的基本概念,掌握虚函数和纯虚函数的概念
使学生掌握C++中函数模板和类模板的使用方法
韶关学院09—10学年第二学期《面向对象程序设计C++》教学进度表
院(系):计算机科学系年级(班):09本④⑤班人数:113学时:72学分:4
课程编号011204700选用教材《C++面向对象程序设计》陈维兴中国铁道出版社
填表日期10年2月26日
周次
起止日期
章节
教学目标
教学形式
备注
1
2
3
4、5
6、7
使学生能用C++预定义的I/O类进行流处理
使学生掌握文件的输入输出方法
成绩评定,考试成绩质量分析
讲授
讲授
讲授
讲授
讲授
讲授
讲授
讲授
讲授
自学
辅导
辅导

《C++面向对象程序设计》 谭浩强 第六章

《C++面向对象程序设计》  谭浩强 第六章
① ② ③
C++
先声明基类point类,并调试之; 再声明派生类circle类,调试之; 最后声明cylinder类,调试之。
6- 5
① 先声明基类point
#include <iostream.h> class point //声明类point {public: point (float x=0, float y=0 ); //有默认值的构造函数 void setPoint (float, float); //设置点坐标 float getX ( ) const { return x; } // 读x 值 float getY ( ) const { return y; } // 读y 值 friend ostream & operator << ( ostream &, const point &); protected: float x,y; }; // 下面定义 point类的成员函数 point :: point (float a, float b) // point的构造函数 { x = a; y = b; } void point :: setPoint (float a, float b) { x =a; y = b; } ostream &operator << (ostream &output, const point &p) { // 重载运算符<< output<<“[x=“<<p.x<<“, y=“<<p.y<<“]”<<endl; return output; }
6Hale Waihona Puke 7③ 最后声明cylinder类

C++程序设计基础第6章 虚函数与多态性

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) : 食肉动物 : 老虎
相关主题
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

point::point(int x,int y) { point::x=x; point::y=y; } point::point(int i) {x=y=i;} main() { point p1; point p2(10,20); point p3(30); return 0; }
动态关联:在运行时才决定运行哪个函数。 优点:灵活,层次高,技巧性高; 缺点:效率低;但由于现在计算机速度很快,所 以一般不再考虑其运行效率问题。 由动态关联支持的多态性称为动态多态性,是 面向对象技术多态性主要说明的问题。 动态多态性:通过继承和虚函数来实现;
int main( ) {Circle c(3.5,6.4,5.2); cout<<"original circle:\nx="<<c.getX()<<", y="<<c.getY()<<", r="<<c.getRadius( ) <<", area="<<c.area( )<<endl; c.setRadius(7.5); c.setPoint(5,5); cout<<"new circle:\\n"<<c; Point &pRef=c; cout<<"pRef:"<<pRef; return 0; }
6.3 虚函数
虚函数的作用是允许在派生类中重新定 义与基类同名的函数,并且可以通过基 类指针或引用来访问基类和派生类中的 同名函数。
例6.2 基类与派生类中有同名函数。
x=3.5, y=6.4, r=5.2, area=84.9486 new circle: Center=[5,5], r=7.5, area=176.714 pRef:[5,5]
(3) 声明Circle的派生类Cylinder
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) {output<<"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); original cylinder: cy1.setPoint(5,5); cout<<"\nnew cylinder:\n"<<cy1; x=3.5, y=6.4, r=5.2, h=10 Point &pRef=cy1; area=496.623, volume=849.486 cout<<"\npRef as a Point:"<<pRef; new cylinder: Circle &cRef=cy1; Center=[5,5], r=7.5, h=15 cout<<"\ncRef as a Circle:"<<cRef; area=1060.29, volume=2650.72 cy1.area( ); cy1.Circle::area( ); return 0; }
基类与派生类的转换
所谓赋值兼容规则是指在需要基类对 象的任何地方都可以使用公有派生 类的对象来替代。 这样,公有派生类实际上就具备 了基类的所有特性,凡基类能解决 的问题,公有派生类也能解决。
• (1)类的引用
(3) 如果函数的参数是基类对象或基类 对象的引用,相应的实参可以用派生 类对象。 (4) 可以把派生类对象的地址赋值给指 向基 类的指针变量。
同一个实现接口,使用不同的实例而执行不同操作
打印机
打印 彩色打印机
打印 黑白打印机
打印效果:彩色
打印效果:黑白 4
多态性的实现方法
• 函数重载实现多态:对同一个函数名,当用不同的实 参调用时,会调用到不同的重载函数版本,因而完成 不同的功能,这是一种多态性的体现。 • 模板实现多态:模板是一类函数或类的样板,通过用 不同的模板实参调用模板,同一个名字可生成不同的 具体函数或具体类,从而实现不同的功能,这也是一 种多态性的体现。 • 虚函数实现多态:通过动态束定机制,使相同的函数 调用代码可能调用不同的类(基类或派生类)的虚函 数,从而完成不同的功能,这又是一种多态性的体现。
静态多态性
• 在没有类层次的场合,使用函数重载的 方式实现静态多态性。各个重载函数名 称相同,但参数表应在参数个数、类型 和次序上有所不同。编译器根据参数表 来识别各个重载函数
#include<iostream> using namespace std; class point{ int x,y; public: point(); point(int x,int y); point(int i); }; point::point() { x=0; y=0; }
(2) 声明派生类Circle
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) {output<<"Center=["<<c.x<<","<<c.y<<"],r="<<c.radius<<",area="<<c.area( )<<endl; return output; }
声明基类Point类
数据成员:x,y 成员函数:构造函数(带默认参数),setpoint,getx(const),gety(const) 重载运算符“<<”
声明派生类Circle
数据成员:radius 成员函数:构造函数(带默认参数),setradius,getradius(const),area 重载运算符“<<”
声明Circle的派生类Cylinder
数据成员:height 成员函数:构造函数(带默认参数),setheight,getheight(const),area(), volumn() 重载运算符“<<”
相关文档
最新文档