C程序设计--对象分册(第3章)潘修改.ppt_第1页
C程序设计--对象分册(第3章)潘修改.ppt_第2页
C程序设计--对象分册(第3章)潘修改.ppt_第3页
C程序设计--对象分册(第3章)潘修改.ppt_第4页
C程序设计--对象分册(第3章)潘修改.ppt_第5页
已阅读5页,还剩51页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第3章多态性 n本章学习重点掌握内容: n多态的概念和作用,多态的实现方法 n常见运算符的重载 n静态联编和动态联编 n虚函数、纯虚函数和抽象基类的概念和用法 n虚析构函数的概念和作用,虚析构函数的用法 1 第3章多态性 n3.1多态性的概念 n3.2 运算符重载 n3.3联编和虚函数 n3.4 纯虚函数和抽象类 n3.5 综合应用实例 2 3.1多态性的概念 n多态性(Polymorphism)是面向对象程序设计的重 要特性之一,它与封装性和继承性一起构成了面向对象 程序设计的三大特性。多态性是指当不同的对象收到相 同的消息时,产生不同的动作。利用多态性可以设计和 实现一个易于扩展的系统。 n在面向对象程序设计里多态性主要体现在:向不同的 对象发送同一个消息,不同的对象在接收时会产生不同 的行为(即方法)。也就是说,每个对象可以用自己的方 式去响应共同的消息。C+支持两种形式的多态性,一 种是编译时的多态性,称为静态联编。 3 3.2.1 运算符重载概述 在以前的学习中,C+中预定义的运算符的操作对象只能是基本数据 类型如int或float等。实际上,对于很多用户自定义的类型(如类),也 需要有类似的运算操作。 例如复数类Complex。 class Complex public: Complex () real=image=0; Complex (double r, double i) real = r, image = i; void Print(); private: double real, image; ; 4 3.2.1 运算符重载概述 void Complex:Print() if(image using namespace std; class Complex public: Complex(double r=0, double i=0) real = r, image = i; void print() if(image0) cout class Complex public: Complex (double r = 0, double i= 0) real = r; image = i; void print(); Complex operator+ ( const Complex private: double real, image; ; 9 void Complex:print() if(image using namespace std; static int mon_day=31,28,31,30,31,30,31,31,30,31,30,31 ; class CDate public: CDate (int m=0,int d=0,int y=0) month=m;day=d;year=y; void display() cout mon_daydt.month-1) dt.day-=mon_daydt.month-1; if(+dt.month= =13) dt.month=1; dt.year+; return dt; int main() CDate olddate(2,20,99); CDate newdate; newdate=21+olddate; newdate.display(); return 0; 运行结果: 3/13/99 12 3.2.3 赋值运算符重载 在C+中有两种类型的赋值运算符:一类是是“=”即直接赋值的运算符 。另一类是“+=”和“-=”等复合赋值运算符。下面以“=”运算符为例子讨 论。复合赋值运算符的重载作为练习,读者可以自行推导。下面分别进 行讨论。 【例3.5】 “=”运算符重载的示例。 #include #include using namespace std; class CMessage public: CMessage( ) buffer=new char(0); CMessage( ) delete buffer; 13 void display( ) cout using namespace std; class Counter public: Counter(int i=0) v=i; Counter operator +(); /前置单目运算符 Counter operator +(int); /后置单目运算符 void getValue()cout #include using namespace std; class MyCharArray public: MyCharArray(int m) 19 len=m; str=new charlen; memset(str,0,len); MyCharArray(char *s) str=new charstrlen(s)+1; strcpy(str,s); len=strlen(s); MyCharArray() delete str; char if(nlen-1) cout using namespace std; Class Money public: Money(double d) value=d; void show() cout using namespace std; class Money /人民币类 public: Money(double d) Value=d; void show() cout using namespace std; const double PI=3.14159; class CPoint public: CPoint(double x, double y) this-x=x; this-y=y; double area( ) return 0; private: double x,y; ; class CCircle : public CPoint public: CCircle(double x, double y,double radius) : CPoint(x,y) this-radius = radius; double area( ) return PI*radius*radius; private: double radius; ; 【例3.10】虚函数的引入 31 int main() CPoint point(3.0,4.0); CCircle circle(5.0,6.0,10); coutarea()area()area() using namespace std; const double PI=3.14159; class CPoint public: CPoint(double x, double y) this-x=x; this-y=y; virtual double area( ) return 0; private: double x,y; ; 36 class CCircle : public CPoint public: CCircle(double x, double y,double radius) : CPoint(x,y) this-radius = radius; double area( ) return PI*radius*radius; private: double radius; ; int main() CPoint point(3.0,4.0); CCircle circle(5.0,6.0,10); coutarea()area()area() using namespace std; const double PI=3.14159; class CPoint public: CPoint(double x, double y) this-x=x; this-y=y; virtual double area( ) return 0; private: double x,y; ; class CCircle : public CPoint public: CCircle(double x, double y,double radius) : CPoint(x,y) this-radius = radius; double area( ) return PI*radius*radius; private: double radius; ; class CRectangle:public CPoint public: CRectangle(double x, double y,double width,double height ):CPoint(x,y) this-width=width; this-height=height; double area( ) return width*height; private: double width,height; ; 39 int main() CPoint point(3.0,4.0); CCircle circle(5.0,6.0,10); CRectangle rect(1.2,3.2,5.0,6.0); CPoint *ptr_point= coutarea()area()area()area(),调用的是不同的area函数。同一 个表达式“ptr_point-area()”在不同的场合可 以执行不同的行为,这就是“多态性”的含义 。 40 3.3.4使用引用变量的多态性 n除了可以用一个基类指针指向派生类对象之外,我们还可以使用一 个基类引用,将它初始化到派生类的对象。那么,通过引用变量来 调用虚函数,同样可以体现多态性。 【例3.13】引用变量的多态性。 #include using namespace std; const double PI=3.14159; class CPoint public: CPoint(double x, double y) this-x=x; this-y=y; virtual double area( ) return 0; private: double x,y; ; class CCircle : public CPoint public: CCircle(double x, double y,double radius) : CPoint(x,y) this-radius = radius; double area( ) return PI*radius*radius; private: double radius; ; 41 int main() CPoint point(3.0,4.0); CCircle circle(5.0,6.0,10); cout using namespace std; const double PI=3.14159; class CPoint public: CPoint(double x, double y) this-x=x; this-y=y; virtual double area( ) return 0; private: double x,y; ; class CCircle : public CPoint public: CCircle(double x, double y,double radius) : CPoint(x,y) this-radius = radius; double area( ) return PI*radius*radius; private: double radius; ; int main() CPoint point(3.0,4.0); CCircle circle(5.0,6.0,10); coutarea()时,由于ptr_point是一个基类指针,编译器自动绑 定基类的area函数代码。这就是两个例子中被调用的area函数是基类 的成员函数的原因。 45 第二,对于【例3.11】、【例3.12】、【例3.13】,它们符合动态联编的前 提,则编译器在执行过程中遇到virtual关键字的时候,将自动执行动态联编 的机制, 1首先为这些包含virtual函数的类(注意不是对象)建立一张虚函数表 VTABLE。在这些虚函数表中,编译器将依次按照函数声明次序记录类的所 有虚函数的代码在内存中存储区域的首地址。 2同时在每个带有虚函数的类中增加一个称之为vpointer的指针,简称vptr ,这个指针指向这个类的VTABLE。 3派生类继承了基类的虚函数表VTABLE,并且加以修正:如果派生类覆盖 了继承到的虚函数,则VTABLE中登记的就是派生类改写后的虚函数代码的 首地址而非基类的虚函数代码的首地址;如果派生类新增了虚函数,则在 VTABLE中增加一项,记录新增虚函数的代码的首地址。 3在编译的时候,仅仅针对非虚的成员函数进行代码绑定,而暂时不会绑 定虚函数。 4在程序运行时,每一个对象创建时,都复制一份vptr指针保存在自己的 内存空间,一般置于对象的起始位置。 5当指向派生类对象的基类指针(引用)来调用某个虚函数时,才来做代 码绑定工作:先根据指针(引用)找到它所指向的派生类对象,然后,从对 象中获取vptr指针,从而找到VTABLE;从VTABLE查找到该虚函数的代码在 内存空间中存储区域的首地址,进一步找到它的代码,最后实现绑定和调用 。 注意,上述调用过程中是通过派生类的对象来找到最终被调用的虚函数代码 的,所以,被调用的只能是派生类的成员函数!这就是C+中动态联编(多 态性)的实现机制。 46 3.3.7 虚析构函数 虚析构函数的声明语法为 : virtual 类名(); 【例3.15】虚析构函数的用法和作用示例。 #include #include using namespace std; class CEmployee public: CEmployee(char *Name, int Age); virtual CEmployee(); private: char *name; int age; ; CEmployee:CEmployee(char *Name, int Age) name=new charstrlen(Name)+ 1 ; strcpy(name, Name); age = Age; CEmployee:CEmployee() cout 函数名(参数表) = 0; 其他函数的声明; . ; 在使用抽象类的时候,有下面三种情况需要注意: (1)抽象类只能用作其他类的基类,抽象类不能建立对象。 (2)抽象类不能用作函数参数类型、函数返回值类型或显式转换的 类型。 (3)可以声明抽象类的指针和引用。 52 【例3.16】抽象类示例。 #include using namespace std; class CPerson public: virtual void PrintInfo() coutPrintInfo(); person-DisplaySalary(12,1800.35); person = person-PrintInfo(); person-DisplaySalary(12,1300.45); person = person-PrintInfo(); person-DisplaySalary(12,1700.78); return 0; 运行结果: 工人 工人全年的工资是:21604.2 教师 教师全年的工资是:15605.4 司机 司机全年的工资是:20409.4 CPerson类中的虚函数DisplaySalary(int m,double s)仅起到为派生类提供一个一致的接口的作用, 派生类中重定义的DisplaySalary(int m,double s) 用于决定以什么样的方式计算工资。由于在 CPerson类中不能对此做出决定,因此被说明为纯 虚函数。 由此可见,赋值兼容规则使人们可将工人、教师 和司机等都视为人类的对象,多态性又保证了函 数DisplaySalary(int m,double s)在对不同的人群 计算工资时,无须关心当前正在计算类人。在需 要时,函数DisplaySalary(int m,double s)可从这 些不同人类的子类对象那里获得该对象的工资。 54 3.5 综合应用实例 【实例一】设计一个字符串类。封装一个不定长字符串并实现字符串的基本操作。 要求如下: 1定义一个串类Cstring,建立适当的构造函数,构造函数原形如下: Cstring :C

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论