1、第13章 C到C+第第13章章 C到到C+13.1 面向对象技术面向对象技术13.2 改进的改进的C语言语言 13.3 C+的输入与输出的输入与输出 13.4 类与对象类与对象 13.5 Windows编程基础编程基础 13.6 程序设计举例程序设计举例 第13章 C到C+13.1 面向对象技术面向对象技术 13.1.1 面向对象技术的由来和发展面向对象技术的由来和发展 面向对象技术产生的背景与结构化程序设计方法产生的背景类似,面向对象程序设计方法(OOP)是在结构化程序设计方法的基础上发展而来的。第13章 C到C+13.1.2 面向对象技术的两大要素面向对象技术的两大要素 1.对象对象 从概
2、念上讲,对象代表着正在创建系统中的一个实体。从形式上讲,对象是待处理的程序单元,是数据和方法的封装体。在C+中是数据成员和成员函数的封装体。方法由若干操作构成。对象实现了信息隐藏,方法的具体实现外部是不可见的,封装的目的是阻止非法访问。对象通过消息与另一个对象传递信息。消息与方法一一对应,在C+中,消息就是成员函数的调用。第13章 C到C+2.类类 类是对象的抽象及描述,是创建对象的样板,它包含着一类对象的数据描述和方法定义。一个类的所有对象都有相同的数据结构,共享相同的方法,而各个对象有各自不同的状态,类是所有对象的共同行为和不同状态的集合。由一个特定的类所创建的对象称为这个类的实例。第13
3、章 C到C+13.1.3 面向对象技术的三大机制面向对象技术的三大机制 1.封装封装 封装的对象是数据和方法,支持数据封装就是支持数据抽象。在C+中,类是支持数据封装的工具,对象则是数据封装的实现。没有封装,就没有面向对象技术。另外,封装还提供一种对数据访问严格控制的机制。因此,数据将被隐藏在封装体中,该封装体通过操作接口与外界交换信息。第13章 C到C+2.继承继承 类提供了说明一组对象结构的机制。借助于继承这一重要机制,已存在的类具有建立子类的能力,进而建立类的层次,扩充类的定义。继承提供了创建新类的一种方法,一个新类可以通过对已有类进行修改和扩充来定义。从一个类继承定义的新类,将继承已有
4、类的方法和属性,并且可添加不包含在父类中的新方法和属性。新类被称为已有类的子类,又称为派生类,已有类称为新类的父类,又称为基类。C+中允许单继承和多继承,一个类可以根据需要生成派生类。第13章 C到C+3.多态多态 多态是指相同的语法结构可以代表不同类型的实体或者对不同类型的实体进行操作,即发出同样的消息被不同对象接收时导致完全不同的行为。C+允许函数名和运算符重载,允许一个相同的标识符或运算符代表多个不同实现的函数,这是编译时的多态性。C+中可以定义虚函数,通过定义虚函数来支持动态联编。动态联编是另一类重要的多态性,多态性形成由父类和它们的子类组成的一个树型结构。在这个树中的每一个子类可接收
5、一个或多个具有相同名字的消息。当一个消息被这个树中一个类的一个对象接收时,这个对象动态地决定给予子类对象的消息的某种用法。这是执行时的多态性。第13章 C到C+13.1.4 面向对象程序设计面向对象程序设计 面向对象的程序设计方法是目前最先进的程序设计方法。面向对象程序设计模拟人类认识问题较高、较广层次的过程。结构化程序设计强调功能抽象,程序的模块化,基于功能进行模块分解;面向对象程序设计以数据抽象为基础,综合了功能抽象和数据抽象,基于数据抽象进行模块分解。第13章 C到C+13.2 改进的改进的C语言语言 13.2.1 C+程序程序 1.C+程序一般结构程序一般结构/C+程序的简单实例inc
6、lude iostream.hmain()double x,y;coutxy;double z;z=x+y;coutx+y=zn;第13章 C到C+C+程序的一般结构如下:文件包含;基类定义;派生类定义;成员函数定义;非成员函数原型说明;主函数;非成员函数。第13章 C到C+2.C+程序的实现程序的实现 1)编辑C+源程序 启动Visual C+后,出现“Microsoft Developer Studio”窗口,见图13-1。该窗口有File、Edit、View、Insert、Project、Build、Tools、Window及Help 9 个菜单项。第13章 C到C+图 13-1 第13
7、章 C到C+2)编译连接和运行源程序编译连接和运行源程序 选择菜单项Build,出现Build的下拉式菜单,在该下拉式菜单中选择“Compile*”菜单项,这时系统开始对当前的源程序进行编译。在编译的过程中,将所发现的错误显示在屏幕下方的“Build”窗口中。所显示的出错信息指出该错误所在的行号和该错误的性质,程序员可根据这些信息采用全屏幕编辑方式修改程序。当用鼠标双击出错信息提示行时,该错误信息对应的行将加亮显示,或在该行前面用一个箭头加以指示。往往因为一个错误而出现多行出错信息,因此,常常在修改一条错误后,再重新编译,如果有错误,再继续修改,直到没有错误为止。第13章 C到C+编译通过,显
8、示错误信息的窗口内将显示如下信息:*.obj-0 error(s),0 warning(s)编译无错误后,再进行连接。这时选择“Build”菜单中的“Build*.exe”选项。同样,对出现的错误要根据出错信息行中显示的内容进行修改,直到连接无错误为止。这时,在“Build”窗口会显示如下信息:*.exe-0error(s),0 warning(s)这说明编译、连接成功,并生成以源文件名为名字的可执行文件(.exe)。第13章 C到C+13.2.2 常规改进常规改进 1新增的关键字新增的关键字asm catch class delete friend inline newoperator pr
9、ivate protected public template this virtual在将原来用C写的程序用C+编译之前,应把与上述关键字同名的标识符改名。第13章 C到C+2.注释注释 即用“/”导引出单行注释。当然,C中原有的/*和*/注释方法,仍可使用,并且常用于多行注释情况。第13章 C到C+3类型转换类型转换C+支持两种不同的类型转换形式:int i=123;long l=(long)i;/C的类型转换long m=long(i);/C+的新风格 C+新风格的类型转换从形式上看像是一个函数调用,所以其可读性较好。而且,这种形式也适合于用定义函数来实现的用户定义类型的转换。第13章
10、C到C+4灵活的声明灵活的声明 C+程序中的变量,即对象,要求在使用之前被说明,并可以放在任何语句位置,不必非放在程序段的开始处。这样,可以随用随定义,这也是C+封装的要求。而且在远离数据项被使用处的变量声明易引起混淆或导致错误。第13章 C到C+5const C+中,类型限定符const用来表示常量。所以,C+中的常量是可以有类型的,程序员不必再用#define创建无类型常量。例如:const int size=100;size被声明成const的变量,实际是常量,其值在程序中是用任何方法都不可修改的。ANSI C从C+中借用了const 的概念,但实现方法有所不同。第13章 C到C+6、s
11、truct C+的struct后的标识符可看作是类型名,所以定义某个struct变量比C中更加直观。例如,在C中:struct point int x;int y;struct point p;而在C+中:struct point int x;int y;point p;union的情况也是如此。为了保持兼容性,C+仍然接受老用法。在后面会看到,C+的类就是对C中struct的扩充。第13章 C到C+7.作用域分辨运算符作用域分辨运算符“”“”是作用域分辨运算符,它用于访问在当前作用域中被隐藏的数据项。例如:int a;int main()float a;a=1.5;/访问当前作用域的a a=
12、2;/访问全局域的a 第13章 C到C+13.2.3 C+的动态内存分配的动态内存分配 C程序中,动态内存分配是通过调用诸如malloc()和free()等库函数来实现,而C+给出了用new和delete运算符进行动态内存分配的新方法。第13章 C到C+void func()int*i=new int;/为指针i分配存储空间*i=10;couti;delete i;/释放i指向的存储空间以下是C+程序中用新方法实现动态内存分配的例子。第13章 C到C+用传统的C程序实现是这样的:void func(void)int *i;i=malloc(sizeof(int);*i=10;printf(%d
13、,*i);free(i);第13章 C到C+13.2.4 引用引用 C程序中,函数在调用时参数是通过值来传递的,这就是说函数的参数不具备返回值的能力,只有函数本身才能有返回值(用return语句)。如果需要函数的参数具有返回值的能力,往往是借用指针来实现的。C+程序通过引入引用(Reference)机制,可直接实现数据的双向传递。例如:void swapint(int&a,int&b)/引用例 int temp=a;a=b;b=temp;第13章 C到C+调用该函数的C+方法为:swapint(x,y);运算符“&”表示引用,可以把参数a、b看作是调用实参的别名,C+自动把x、y的地址作为参数
14、传递给swapint()函数,形参与实参共享存储单元。当大的结构(如用户定义类的对象)被传递给函数时,使用引用参数可使得参数传递效率得到提高。若不需改变参数的值,可用const对参数说明加以限定,从而保护数据的安全性。例如:void getdata(const int&data)第13章 C到C+13.2.5 C+中的函数中的函数 1.main()C并无特别规定main()函数的格式,因为通常并不关心返回何种状态给操作系统。然而,C+却要求main()函数匹配下面两种原型之一:Void main()int main(int argc,char*argv)第13章 C到C+2.函数原型函数原型
15、函数原型(prototyping)的概念在前面章节已提及,其实ANSI C正是从C+中借用了这一做法。函数原型实际上就是对函数的头格式进行说明,包含函数名、参数及返回值类型。传统C中的函数说明只是定义函数的返回值的类型,并不涉及参数,如:int something();而在C+中的函数说明应是详细的头格式:int something(char*str,unsigned int len);第13章 C到C+3.内联函数内联函数 当函数定义是由inline开头时,表明此函数为内联函数。编译后,它不是单独一段可调用的代码,而是被插入在对该函数的每一次调用处,从而完成与函数调用相同的功能。例如:inl
16、ine int sum(int a,int b)return a+b;这样函数调用无需栈,代码重用。第13章 C到C+4缺省参数值缺省参数值 C+对C函数的一大重要的改进之一就是可以为函数定义缺省的参数值。看下面的程序代码:void delay(int loops=1000);/函数原型,给出缺省的参数值 void delay(int loops)/函数定义 for(int i=0;iloops;i+);第13章 C到C+函数原型中给出了loops的缺省值,所以若调用delay函数而并没指定loops的值,程序自动取缺省值1000进行处理。例如:delay(4500);/loops值为4500
17、delay();/loops值为1000 一个C+函数可以有多个缺省参数,并且C+要求缺省参数必须连续地放在函数参数表的尾部。当调用具有多个缺省参数时,只能由左向右匹配,并且必须是连续的。第13章 C到C+13.2.6 重载重载 1函数的重载函数的重载 早期的C语言要求每个函数必须有惟一的命名,这使功能类似的函数名字不统一,通常给程序员带来不便。例如,下面是三个分别对int、long、double三种类型的数取绝对值的C函数:int abs(int i);long labs(long l);double fabs(double d);第13章 C到C+使用C+重载技术后,使用相同的函数名字,就
18、非常直观。int abs(int i);long abs(long l);double abs(double d);重载函数的特点是名字相同,参数个数和类型、返回值类型会有不同。那么,系统是如何区分使用同一个名字的重载函数的呢?实际上,相同的名字在程序编译后的内部名字是不同的,这就是C+所做的名字变异。对于重载运算符也有同样的情况。如果所调用的函数的参数类型、个数与函数说明中的某一个函数相匹配,就调用相应的函数;如果找不到相应的函数说明,就调用最便于进行类型转换的那个函数。第13章 C到C+2.运算符重载运算符重载 typedef struct double r,i;complex;compl
19、ex operator+(complex c1,complex c2)complex t;t.r=c 1.r+c2.r;t.i=c 1.i+c2.i;return(t);先看一个例子。第13章 C到C+用operator后跟运算符号来定义重载运算符函数。重载运算符的使用,如同运算符原来的使用规则。例如:complex x,y,sum;sum=x+y;显然,通过重载,C+的语句更易于理解。第13章 C到C+13.3 C+的输入与输出的输入与输出 13.3.1 C+流类结构流类结构 1.iostream库库 iostream库中具有streambuf和ios两个平行的类,这都是基本的类,分别完成不
20、同的工作。streambuf类提供基本流操作,但不提供格式支持。类ios为格式化I/O提供基本操作。第13章 C到C+2.标准流标准流 iostream.h说明了标准流对象cin、cout、cerr与clog。在包含iostream.h以后,这些流对象就已经自动建立并打开了。cin是标准输入流,对应于C的stdin;cout是标准输出流,对应于C的stdout;cerr和clog流被连到标准输出上对应于C的stderr。cerr和clog之间的区别是cerr没有缓冲,发送给它的任何输出立即被执行,而clog只有当缓冲区满时才有输出。缺省时,C+标准流被连到控制台上。第13章 C到C+13.3.
21、2 基本基本I/O操作操作 1.输出输出插入符插入符“”“”的左操作数为标准输出流对象,右操作数为待输出的某类型值。例如:coutHello!n;/输出Hello!,并换行 这时“”“”的左操作数为标准输入流,右操作数为行输入量。它比scanf()函数更紧凑,且可读性更好,也不易出错。例如:cinx;从cin输入值到x。注意它与scanf()函数不同,x前并没有地址运算符,与插入符类似,提取符“”也支持连写。程序员可以为自己定义的类(型)建立相应的插入和提取函数。第13章 C到C+13.3.3 格式化格式化I/O 1.用用ios成员函数进行格式化成员函数进行格式化 在iostream.h中,有
22、如下有关格式化标志的枚举类型定义:enumskipws=0 x0001,/跳过输入中的空白字符 left=0 x0002,/输出数据左对齐 right=0 x0004,/输出数据右对齐 internal=0 x0008,/数据符号左对齐,数据本身右对齐 dec=0 x0010,/转换基数为十进制形式 第13章 C到C+oct=0 x0020,/转换基数为八进制形式 hex=0 x0040,/转换基数为十六进制形式 showbase=0 x0080,/输出的数值数据全面带基数符号(0或0 x)showpoint=0 x0100,/浮点数输出带小数点 uppercase=0 x0200,/用大写字
23、母输出十六进制数值 showpos=0 x0400,/正数全面带“+”号 scientific=0 x0800,/浮点数输出采用科学表示法 fixed=0 x1000,/浮点数输出采用定点熟形式 unitbuf=0 x2000,/完成操作后立即刷新缓冲区 stdio=0 x4000 /完成操作后刷新stdout,stderr;第13章 C到C+格式标志存放于一个long整数中,要设置它可用ios的setf()函数,其一般格式为:long setf(long flags);该函数设置参数flags所指定的标志,返回格式更新前的标志。例如,要设置showbase标志,可使用如下语句:stream.
24、setf(ios showbase);/其中stream是所涉及的流 实际上,还可以一次调用setf()来同时设置多个标志。例如:cout.setf(ios showpos|ios scientific);清除标志可用unsetf()函数完成,其原型与setf()类似。第13章 C到C+用flags()函数得到当前标志值和设置新标志,分别具有以下两种原型:long flags(void);long flags(long flags);除了标志外,格式输出还可设置域宽、填充字符及输出精度。其原型分别为:int width(int len);char fill(char ch);int preci
25、sion(int num);第13章 C到C+请编译运行下面这段程序:include iostream.hVoid maincout.setf(ios showpos|ios scientific);cout123123.12n;cout.precision(2);cout.width(10);cout123123.12n;cout.fill();cout.width(10);cout123123.12;第13章 C到C+运行结果为:+123+1.2312e+02 +123 +1.23e+02#+123#+1.23e+02 第13章 C到C+2用操作子进行格式化用操作子进行格式化 流类库所定义
26、的操作子如下:dec、hex、oct:数值数据采用十进制或十六进制、八进制表示。setbase(int n):设置数制转换基数为n,n为0、8、10或16,0表示使用缺省基数。ws:提取空白符。ends:插入空字符。flush:刷新与流相关联的缓冲区。第13章 C到C+resetiosflags(long):清除参数所指定的标志位。setiosflags(long):设置参数所指定的标志位。setfill(int):设置填充字符。setsprecision(int):设置浮点数输出的有效数字个数。setw(int):设置输出数据项的域宽。例如:int i=1234;coutsetw(12)ie
27、ndl;输出结果:1234 第13章 C到C+13.4 类与对象类与对象 13.4.1 类的定义类的定义 类的定义格式为:class 类名public:成员函数或数据成员的说明 private:成员函数或数据成员的说明;各个成员函数的实现 第13章 C到C+其中,class是定义类的关键字。类名是一标识符,通常用“T”字母开始的字符串作为类名,T用来表示类,以示与对象、函数名区别。花括号内是类的说明部分(包括前面的类头),说明该类的成员。第13章 C到C+从访问权限上来分,类的成员可分为公有的(public)、私有的(private)和保护的(protected)三类。这里,先讨论前两类,保护
28、的成员在继承性小节中讨论。公有的成员用public来说明。公有部分往往是一些操作(即成员函数),它是提供给用户的接口功能,这部分成员可以在程序中引用。私有的成员用private来说明。私有部分通常是一些数据成员,这些成员是用来描述该类中的对象的属性的,用户是无法访问它们的,只有成员函数或经特殊说明的函数才可以引用它们,它们是被隐藏的部分。第13章 C到C+例如,下面给出一个关于日期的类的定义。该类是对日期抽象,该类的对象将是某一个具体日期。日期类的说明部分:class TDate public:void SetDate(int y,int m,int d);int IsLeap Year();
29、void Print();private:int year,month,day;第13章 C到C+类名为TDate,该类共有6个成员。其中3个是公有成员,它们都是成员函数。SetDate()函数是设置日期的,用它来使对象获取值。IsLeapYear()函数是一个用来判断是否是闰年的函数,它的返回值为1表示该年是闰年,返回值为0表示该年不是闰年。Print()函数用来将日期输出显示。关于这三个函数的功能可通过下面的实现部分看出。还有三个私有成员,它们是int型变量year、month和day。第13章 C到C+日期类的实现部分:void TDate SetDate(int y,int m,int
30、 d)year=y;month=m;day=d;int TDate IsLeapYear(1)return(year%4=0&year%100!=0)|(year%400=0);void TDate Print()coutyear.monthdayendl;第13章 C到C+关于日期类还可如下定义:class TDatepublic:void SetDate(int y,int m,int d)year=y;month=m;day=d;int IsLeapYear()return(year%4=0&year%100!=0)|(year%400=0);void Print()coutyear.m
31、onth.dayendl;private:int year,month,day;第13章 C到C+说明:(1)在类体中不允许对所定义的数据成员进行初始化。例如,对日期类TDate类中,下面的定义是错误的:class TDate public:private:int year(2000),month(2),day(18);这里,不该对数据成员year、month和day进行初始化。第13章 C到C+(2)类中的数据成员的类型可以是任意的,包含整型、浮点型、字符型、数组、指针和引用等。也可以是对象,另一类的对象,但是自身类的对象是不可以的,而自身类的指针或引用又是可以的。当一个类的对象作为这个类的
32、成员时,如果另一个类的定义在后,需要提前说明。(3)一般地,在类体内先说明公有成员,它们是用户所关心的;后说明私有成员,它们是用户不感兴趣的。在说明数据成员时,一般按数据成员的类型大小,由小至大说明,这样可提高时空利用率。第13章 C到C+(4)经常习惯地将类定义的说明部分或者整个定义部分(包含实现部分)放到一个头文件中。后面引用起来比较方便。(5)由于抽象数据类型的要求,C+控制了对类成员的存取,对类的私有数据成员的访问只能通过其公有的成员函数进行,因此会造成运行效率的降低。但没有关系,在不得已的情况下,C+也可以不遵循面向对象的原则,去直接访问类的私有成员,这就是友元(friend)所能做
33、到的。一个类可以允许其它类或函数访问其私有数据,具有这种权力的其它类或函数应当显式地在该类中定义为friend(友元)。友元打破了封装。第13章 C到C+13.4.2 对象的定义对象的定义 对象是类的实例,对象属于某个已知的类。因此,定义对象之前,一定要先定义好该对象的类。对象在确定了它的类以后,其定义格式如下:类名 对象名表;第13章 C到C+类名是待定的对象所属的类的名字,即所定义的对象是该类类型的对象。对象名表是用逗号分隔的对象名。对象名表中,可以是一般的对象名,还可以是指向对象的指针名或引用名,也可以是对象数组名。例如:TDate date1,date2,*Pdate,date31;其
34、中,TDate为日期类的类名,date1和date2是一般的对象名,*Pdate是指向对象的指针,date是对象数组的数组名,它有31个元素,每个元素都是一个对象。这里所说的对象都是TDate类的对象。第13章 C到C+一个对象的成员就是该对象的类所定义的成员。对象成员有数据成员和成员函数,一般对象的成员表示如下:对象名.成员名 或者 对象名.成员名(参数表)前者用来表示数据成员,后者用来表示成员函数。例如,date1的成员可表示为:date1.year、date1.month、date1.day分别表示TDate类的date1对象的year成员、month成员和day成员。date1.Set
35、Date(int y,int m,int d)表示TDate类的date1对象的成员函数SeaDate()。这里,“.”是一个运算符,该运算符的功能是得到对象的成员。第13章 C到C+13.4.3 构造函数和析构函数构造函数和析构函数 构造函数和析构函数是在类体中说明的两种特殊的成员函数。构造函数的功能是在创建对象时,使用给定的值来将对象初始化。析构函数的功能是用来释放一个对象的。在对象删除前,用它来做一些清理工作,它与构造函数的功能正好相反。第13章 C到C+下面将重新定义前面讲过的日期类:class TDate1public:TDate1(int y,int m,int d);TDate1
36、();void Print();private:int year,month,day;第13章 C到C+TDate1 TDate1(int y,int m,intd)year=y;month=m;day=d;coutConstructor called.n;TDate1 TDate1()coutDestructor called.n;void TDate1 Print()coutyear.month.dayendl;第13章 C到C+构造函数的特点如下:(1)构造函数是成员函数,函数体可写在类体内,也可写在类体外。(2)构造函数是一个特殊的函数,该函数的名字与类名相同,该函数不指定类型说明,它
37、有隐含的返回值,该值由系统内部使用。该函数可以有一个参数,也可以有多个参数。(3)构造函数可以重载,即可以定义多个参数个数不同的函数。(4)程序中不能直接调用构造函数,在创建对象时系统自动调用构造函数。第13章 C到C+析构函数的特点如下:(1)析构函数是一个特殊的成员函数,它的名字同类名,并在前面加“”字符,用来与构造函数加以区别。析构函数不指定数据类型,并且也没有参数。(2)一个类中只能定义一个析构函数,析构函数不能重载。(3)析构函数可以被调用,也可以由系统调用。在下面两种情况下,析构函数会被自动调用。一是如果一个对象被定义在一个函数体内,则当这个函数结束时,该对象的析构函数被自动调用;
38、二是当一个对象是使用new运算符被动创建的,在使用delete运算符释放它时,delete将会自动调用析构函数。第13章 C到C+若在类定义时没有定义任何构造函数,则编译器自动生成一个不带参数的缺省构造函数,其格式如下 类名 缺省构造函数名()按构造函数的规定,缺省构造函数名同类名。缺省构造函数的这种格式也可以由程序员定义在类体中。在程序中定义一个对象而没有指明初始化,则编译器便按缺省构造函数来初始化该对象,对象的所有数据成员都初始化为零或空。第13章 C到C+同理,如果一个类中没有定义析构函数时,则编译系统也生成一个缺省析构函数,其格式如下:类名 缺省析构函数名()缺省析构函数名也同类名,缺
39、省析构函数是一个空函数。第13章 C到C+13.4.4 继承性继承性 building类的说明如下所示,它用作两个派生类的基类:class building int rooms;int floors;int area;public:void set-rooms(int num);int get-rooms();void set-floors(int num);int get-floors();void set-area(int num);int get-area();第13章 C到C+例如,下面是名为house的派生类,注意building是如何被继承的。/house是基类building的派
40、生类class house:public buildingint bedrooms;int baths;public:void set-bedrooms(int num);int get-bedrooms();void set-baths(int num);int get-baths();第13章 C到C+继承的一般形式是:class 新类名:access 基类名/新的类体 其中,access是可选的,如果出现,它必然是public、protected或private。若缺省,则认为是私有派生private。使用public意味着基类的所有公有元素在继承它的派生类中也是公有的,保护成员能被继承
41、。第13章 C到C+例例 131 继承性实例/程序131,继承性实例includeiostream.hclass building /说明一个基类building int rooms;int floors;int area;public:void set-rooms(int num);int get-rooms();void set-floors(int num);int get-floors();void set-area(int num);int get-area();第13章 C到C+class house:public building /说明一个由基类building 派生出的派生类
42、house int bedrooms;int baths;public:void set-bedrooms(int num);int get-bedrooms();void set-baths(int num);int get-baths();class school:public buiding /说明一个由基类building 派生出的派生类schoolint classrooms;int offices;第13章 C到C+public:void set-classrooms(int num);int get-classrooms();void set-offices(int num);i
43、nt get-offices();void building set-rooms(int num)rooms=num;void building set-floors(int num)floors=num;void building set-area(int num)area=num;int building get-rooms()return rooms;int building get-floors()return floors;第13章 C到C+int building get-area()return area;void house set-bedrooms(int num)bedro
44、oms=num;void house set-baths(int num)baths=num;int house get-bedrooms()return bedrooms;int house get-baths()return baths;void school set-classrooms(int num)classrooms=num;void school set-offices(int num)offices=num;第13章 C到C+int school get-classrooms()return classrooms;int school get-offices()return
45、offices;void main()house h;school s;/定义派生类house和school下的对象h和sh.set-rooms(6);h.set-floor(8);h.set-area(4500);/对对象h进行操作h.set-bedrooms(5);h.set-baths(3);cout这所房屋有h.get-bedrooms();/将对象的卧室数输出cout间卧室!n;第13章 C到C+s.set-rooms(200);s.set-classrooms(180);/对对象s进 行操作s.set-offices(5);s.set-area(25000);cout学校有s.ge
46、t-classrooms();/将对象的教室 数输出coutn间教室!n;cout学校的建筑面积是s.get-area();/将对象的建 筑面积输出 第13章 C到C+13.4.5 运行时的多态性运行时的多态性 1.指向派生类的指针指向派生类的指针 指向基类指针和指向派生类指针是有联系的。若有基类Bclass和Bclass派生的Dclass,则任何指向Bclass对象的指针也可用于指向Dclass对象。例如:Bclass*p;/指向Bclass对象的指针 Bclass b;/Bclass对象 Dclass d;/由Bclass派生的Dclass对象 p=&b;/p指向Bclass对象b P=&
47、d;/p指向Dclass对象d 第13章 C到C+2.虚函数虚函数 虚函数是一个在基类中被说明为virtual,并在一个或多个派生类中被重新定义的函数。虚函数有这样的特性:当用指向基类的指针访问一个虚函数时,C+要根据该基类指针在运行时实际指向的对象类型(有可能指向某个派生类对象)来确定调用哪一个函数。所以,若指向不同的派生类对象,则执行该虚函数的不同版本。这就是所谓通过派生类和虚函数来实现的运行时的多态性。这种在运行时才确定调用哪个函数的性质常被称为动态链接(dynamic binding)。第13章 C到C+实现运行时的多态性应注意的关键几点:(1)要用指向基类的指针。(2)虚函数要求函数
48、原型相同,否则视为重载。(3)虚函数必须是定义类的成员,而不是友元。(4)析构函数允许是虚函数,但构造函数不可以。第13章 C到C+3.纯虚函数及抽象类纯虚函数及抽象类 纯虚函数是在某个基类中说明的虚函数,并且它在该基类中无定义,即真正为虚拟的函数。但该基类的任何派生类都可定义该虚函数的具体实现,从而实现运行时的多态性。一个基类若含有纯虚函数作为其成员,则该基类为抽象类。抽象类的一个重要性质是不可定义抽象类的对象,它的作用就是为派生类定义公共的成员或虚函数。这不仅减少了代码的重复,而且又可实现运行时的多态性。第13章 C到C+13.5.1 Windows程序程序 1Windows程序特点程序特
49、点 Windows程序以窗口为基础,采用图形用户界面和虚拟设备接口,允许动态链接,由消息驱动,通过来自操作系统的消息来处理用户输入,启动一个程序时运行WinMain()函数。13.5 Windows编程基础编程基础 第13章 C到C+2Windows编程方式编程方式 Windows编程有SDK与MFC两种编程方式。SDK编程方式是基于Windows的API函数的类C编程方式,是一种传统的源程序代码编写方式,编写的代码运行效率高,开发难度与开发工作量大。MFC编程方式是基于Windows的MFC类库的编程方式,是一种交互式的可视化的编程方式,编程效率高,开发难度与开发工作量相对较小。第13章 C
50、到C+13.5.2 Windows程序结构程序结构 Windows程序由WinMain()函数与窗口函数组成。WinMain()函数可完成窗口类的注册与初始化以及窗口的建立与显示,同时建立与维护消息循环。窗口函数是消息处理函数,定义程序对接收到的不同消息的响应,是消息处理分支控制语句的集合,包含了程序对各种可能接收到的消息的处理过程。第13章 C到C+13.5.3 一个简单的一个简单的VC+程序程序 例例13-2 画三个填充图形。画三个填充图形。/例13-2,画三个填充图形/GDI程序1.cpp:Defines the entry point for the application.#incl