友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
第三电子书 返回本书目录 加入书签 我的书架 我的书签 TXT全本下载 『收藏到我的浏览器』

C语言实例教程(PDF格式)-第6部分

快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!


和Windows NT,而事实上,Windows 95和Windows NT使用了完全不同 

的内核,对于很多同样的操作,在Windows 95和Windows NT两个操作 

系统下的实现方式是不同,但两个操作系统都提供了同样的Win32应 

用程序编程接口 (API),这样,我们所编写的应用程序只需要和Win32 

应用程序编程接口打交道,而没有必要知道具体的每一个Win32   API 

函数在操作系统中是如何实现的。换一种说法就是,Windows       95和 

Windows NT封装了Win32 API函数的具体实现。  



一个类在定义数据的同时也定义了对这些数据的操作,这些操作称作 

方法 (method)。按照面向对象的定义,方法就是对对象中的数据的访 

问。在C++中,对对象中的数据的访问是通过公有成员函数来进行 

的,这些公有成员函数可以在对象的外部进行调用,它们提供了对象 

的外部接口。而对于这些接口的内部的实现在对象的外部的不可见 

的,这些实现包括了类内部所使用的数据结构和支持公有方法的实现 

的私有成员函数,通常,这些数据成员和成员函数是私有的,它们只 

能为类中成员函数所访问,而不能从类的外部进行访问。  



访问一个方法的过程称为向这个对象发送一个消息 (message),对象 

的工作是靠消息来激发的,对象之间也是通过消息发生联系的,即请 

求其它对象做什么或响应其它对象的请求是通过发送或接收消息来实 

现的。  



  l 注意:  


…………………………………………………………Page 41……………………………………………………………

  l 这里的所说消息和在Windows编程中所常说的消息是两个不同术 

   语,尽管在某些方面两者的确有很多相象之处。  



封装可避免许多维护性问题。如果一个基本数据类型的结构被修改 

了,例如一个链表修改成了一个数组,除类中的访问该数据的方法的 

代码外,软件系统的其余部分是不受影响的,因为基本数据在外部是 

不可见的,只能通过公有方法的接口与基本数据发生联系,改变一个 

类的实现,丝毫不影响使用这个类的程序员,从而大大的减少了应用 

程序出错的可能性。  



                                          



               图2。1  自然世界中的继承关系  



2。1。3 继承  



类支持层次机制,因此我们可以借用可重用性部件来很容易的从一个 

或多个已有类出发,来生产各种更符合我们要求的新类。假设我们从 

类A出发来派生新的类B,那么我们称类A为类B的基类 (base  class), 

类B为类A的派生类 (derived   class),类B继承了类A中的各种行为和 

状态,并可添加自己的成员变量和成员函数。  



我们先来看一个例子,图2。1给出了自然世界中的生物的一种继承层 

次图,最高层次的生物类代表了层次结构中最一般的概念,较低层次 

的类表示由上一层的类 (即其基类)所派生的特殊的概念。如上面的继 

承关系,动物类从其基类—生物类中继承生物类的所有属性和行为, 

并且定义了动物类所特有的属性和行为,类似的,脊椎动物类从动物 

类那儿继承了所有的属性和行为,并且定义了自身特有的属性和行 


…………………………………………………………Page 42……………………………………………………………

为;……,人类从灵长动物类那儿继承了所有的属性和行为,并且定 

义了人类所特有的属性和行为。  



之所以举上面的例子是为了将程序空间和现实生活空间来进行对比, 

结果说明一点,类的继承使得我们可以以一种自然的方式来模拟生活 

空间中的对象的层次结构,也就是说,我们可以以一种符合正常思维 

逻辑的自然的方式来思考和组织应用程序的结构,然后,可以将这个 

结构几乎不作修改或者只需作少量的修改地用面向对象的编程来表 

达,从而大大的缩短了软件系统的开发周期。  



下面我们举一个现实编程中的例子,考虑MFC                (Microsoft  

Foundation  Class  Library,Microsoft基础类库)中的CEdit类,它 

封装了Windows中的编辑框控件,图2。2显示了CEdit类的继承结构。  



                               



              图2。2 类CEdit在MFC中的继承层次  



在图2。2中,类CObject是所有的MFC类的根(根是一个术语,它指在继 

承层次中处于最顶层的类,根是所有继承层次中的类的最终基类), 

在类CObject中提供了功能有:串行化支持、运行库信息、对象诊断 

输出以及与集合类的兼容等。类CCmdTarget从类CObject直接派生, 

它是Microsoft基础类库的消息映射结构的基类,消息映射将命令和 

消息传递给所编写的处理成员函数,这里,命令指来自菜单项、命令 

按钮和加速键的消息。类CWnd提供了MFC中所有窗口类的基本功能 

性,它封装了Windows中的窗口句柄hWnd。类CEdit从CWnd直接派生, 

它提供了对Windows编辑控件的特定支持。  



我们看到,类CEdit本身仅提供了特定于编辑控件的38个成员函数, 

但是,你可以通过类CEdit进行调用的成员函数却多达300多个,事实 

上,这些成员函数中的绝大部分由其基类所提供,其中CWnd就为 

CEdit提供了多达304个成员函数,由于CEdit类继承了其基类的数据 

和方法,因此,可以通过CEdit类调用CWnd类中提供的方法来实现对 

标准Windows窗口的操作。  



继承机制所带来的最大优势在于使软件系统非常的易于扩充,程序员 


…………………………………………………………Page 43……………………………………………………………

不仅可以直接的使用各种已有的类,还可以从这些类方便的派生出新 

的类,新的类继承了基类所包括的所有接口和功能,因此只需要定义 

和实现与基类所提供的功能中不同的那一部分,这大大的降低了软件 

开发的复杂性和费用,因此面向对象的编程方式非常之适合于进行大 

型软件系统的开发。  



降低软件开发的复杂性的意义不仅在于它可以有效的降低软件开发的 

费用,而且还使得在软件系统中出错的可能性大为减少。由于类有着 

清晰的继承层次,因此,我们可以很快的定义出错的代码所处的位 

置,因此能够很快的修正程序中出现的问题。  



继承机制还使得我们可以将与现实生活空间相一致的思维方式应用于 

程序空间,即我们可以在程序设计时使用直观的思维方式设计程序中 

所使用的对象的层次结构,然后,直接将此结构映射到面向对象的程 

序空间,而不需要做任何修改或仅需要作少量修改就可以使用面向对 

象的程序设计方法来实现该结构。这时,编写程序的过程更类似于 

 “搭积木”,我们可以从很多途径来获得到程序所需使用的各种对 

象,然后,将这些对象以一定的层次结构组合起来,从而实现程序的 

逻辑结构。  



2。1。4 多态和虚函数  



在讲述多态之前我们先来看一个问题。仍以前面的图2。2为例,假定 

我们已经定义了一个指向哺乳动物类的实例对象的指针,如下所示:  



CMammal *pMammal  



然后我们定义了一个人类的实例对象和一个狒狒类的实例对象,如下 

所示:  



CHuman Human;  



CBaboon Baboon;  



然后,我们可以将指针pMammal指向Human对象,在C++语言中是可以 

这样做的:  



pMammal=&Human;  



也可以将指针指向Human对象:  



pMammal=&Baboon;  



考查上面的两种情况,我们假定在哺乳动物类、人类和狒狒类中都定 


…………………………………………………………Page 44……………………………………………………………

义了一个Eat  (吃)方法,很显然,当我们使用下面的代码来调用人类 

对象和狒狒类对象的Eat方法时不会遇到什么问题:  



Human。Eat();  



Baboon。Eat();  



但是,现在来考虑下面的代码:  



pMammal…》Eat();  



当pMammal指向不同的对象时,上面的代码将发生什么样的结果。很 

显然,当pMammal指向一个哺乳动物类的实例对象时,上面的代码将 

调用哺乳动物类的Eat方法。但是,当pMammal指向一个人类的实例对 

象时,上面的代码是调用人类的Eat方法呢,还是仍然调用哺乳动物 

类的Eat方法?我们期望的是前面一种情况,这就是类和对象的多态 

性。我们期望,当pMammal指向不同的实例对象时,编译器将根据实 

例对象的类型调用正确的Eat方法。在C++中,类的多态性是通过虚函 

数来实现的。就上面的例子来说,我们将Eat方法定义为一个公有的 

虚函数,这样,当pMammal指针指向一个人类的实例对象时,编译器 

调用的就是人类的Eat方法,当pMammal指针指向一个狒狒类的实例对 

象时,编译器调用的就是狒狒类的实例对象,从而实现了运行时的多 

态。  



在C++中,多态定义为不同函数的同一接口。从这个定义出发,函数 

和操作符的重载也属于多态。  



考虑下面定义的两个函数:  



int print(char*);  



int print(int);  



上面的两个不同函数使用同样的函数名,在C++中,这称为函数的重 

载。这时,若将一个字符指针传递给print函数,如下所示:  



char *sz=〃Hello World!〃;  



print(sz);  



这时,编译器调用的是int  print(char*),如果将一个整型变量传递 

给print函数,如下所示:  



int i=0;  


…………………………………………………………Page 45……………………………………………………………

print(i);  



则编译器调用的是int  print(int)。这种根据所传递的参数的不同而 

调用不同函数的情形也称作多态。  



下面我们来看运算符重载的例子,在下面的过程中,我们为矩阵类重 

载了运算符 “+”:  



CMatrix operator +(CMatrix; CMatix);  



然后使用下面的代码:  



int a=1; b=1; c;  



CMatrix A(3; 3; 0); B(3; 3; 1); C(3; 3);  



c=a+b;  



C=A+B;  



在上面的例子中,我们定义了三个整型变量和三个类CMatrix的实例 

变量,A、B和C均为3'  3的矩阵,其中A中全部元素均置为0,B的全部 

元素均置为1。然后将 “+”运算符作用来整型变量和类CMatirx的实 

例变量。这时,编译器将表达式c=a+b翻译为  



c=operator +(a; b);  



而将表达式C=A+B翻译为  



C=operator +(A; B)  



然后,根据传递参数的不同,调用不同的operator +函数。  



与类和对象的多态不同,对于函数和运算符的多态,是在编译过程中 

完成的,因此我们将它们称为编译时多态,与此相对,将类和对象的 

多态称为运行时多态。  



封装性、继承性和多态性是面向对象编程的三大特征,则开始的时 

候,你也许对它们还没有非常清晰的概念,但这没有什么关系,当你 

使用了一段时间的C++语言,然后再回过头来看这些概念时,你就会 

发现对它们有了更深入的认识和了解。事实上,许多的C++程序正是 

在使用C++语言进行编程已有相当一段时间时才对这三个概念有了正 

确而清晰的认识的。  



  l 注意:  


…………………………………………………………Page 46……………………………………………………………

  l 在前面的过程中,我们多次混用了对象和类这两个术语,事实 

   上,它们之间是有差别的。在C++中,类是一种数据类型,它是一 

   组相同类型的对象的抽象。在类中定义了这一类对象的统一的接 

   口。而对象在C++中是指某一数据类型的一个实例,如下面的代码 

   所示:  



  l Class CBaloon;  



  l CBaloon Baloon1;  



  l CBaloon Baloon2;  



  l CBaloon Baloon3;  



      在上面的代码 中,我们声明了一个类CBaloon,这是所有狒狒 

      对象的抽象,然后,我们使用类来创建了三个不同的实例对 

      象Baloon1、Baloon2和Baloon3。  



      然而,尽管类和对象是两个意义不同的概念,但是,它们在 

      C++语言中是紧密相关的,这使得很多的文档 (包括Visual  

      C++的联机文档)在有些时候也不加 区分的混用这两个术语。 

      读者根据相应的上下文,应该能够很方便的辨明它们具体所 

      指的内容究竟是类还是类的实例对象。  



在随后的小节中,我们将讲述如何在C++中实现上面所说的面向对象 

的编程概念。  



               第二节 类的声明和定义  



本节讲述在声明和定义类及类中的成员变量和成员函数所需注意的问 

题。在本章中,我们使用了传统的C/C++编程风格,即每一个程序都 

以一个名为main的主函数为入口,过去常见的MS…DOS应用程序即是这 

样的。众所周知,Visual C++ 5。0不支持16位MS…DOS编程,但这并不 

意味着我们必须放弃这种编程模式。事实上,我们仍然可以在Visual  

C++  5。0中编译和调试在本章中出现的所有程序,方法是使用Win32  

Console Application (Win32控制台应用程序)来编译它们,Win32控 

制台API提供了字符方式的应用程序的编程接口,并且,我们仍可以 

使用过去所熟知的以main函数为入口的编程方式。除此之外,Win32 

平台为控制台应用程序提供了虚拟的一个标准输入和输出设备 (由于 

Windows程序共享屏幕和其它所有设备,因此不存在在DOS中的那种标 

准输入和输出设备),这样,我们可以使用标准的C语言输入输出函数 

scanf和printf,还可以使用标准的C++语言输入和输出流cin和 


…………………………………………………………Page 47……………………………………………………………

cout。关于控制台应用程序的内容,可以参考本书的相关章节。  



2。2。1 类及其成员变量和成员函数的声明和定义  



在C++中,存在三种类类型:类、结构和联合,它们分别使用三个关 

键字来声明和定义类:class、struct和union。表2。1给出了不同类 

类型之间的差别。  



                   表2。1 三种不同类型的类:类、结构和联合  



                                类     结构         联合  

               



              声明和定义时使用         class  struct  union  

              的关键字  



              默认的成员访问权         私有   公有      公
返回目录 上一页 下一页 回到顶部 1 1
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!