友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!阅读过程发现任何错误请告诉我们,谢谢!! 报告错误
喜书网 返回本书目录 我的书架 我的书签 TXT全本下载 进入书吧 加入书签

C语言实例教程(PDF格式)-第8章

按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!




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

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

现的。  



  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;  



      在上面的代码 中,我们声明了
返回目录 上一页 下一页 回到顶部 0 0
未阅读完?加入书签已便下次继续阅读!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!