8.1 面向对象程序设计方法概述 (属于概念性的,可以跳过,不懂概念的看看就行了)

重点记住

c++三个特点:封装,继承和多态性 (要是问三个就回答这个)

面向对象的四个特点:抽象,封装,继承和多态性 (要是问四个个就回答这个)

类是实现面向对象程序设计的基础,c++对C重要改进是增加了“类“。类是C++的灵魂,不掌握类就不掌握C++

C++支持**面向过程**, 基于对象面向对象 三种程序设计方法。如果问的是两个,就是**面向过程**和**面向对象** 。

面向过程

程序 = 算法 + 数据结构

基于对象和面向对象

对象 = 算法 + 数据结构
程序 = 很多个对象 + 消息 (消息可以理解为让对象做出行为的命令)
对象两个要素:属性和行为
对象由数据和函数(即操作代码)组成 数据体现了属性这个要素,用函数来定义行为这个要素,通过调用函数名来让对象做出行为。
封装,把对象的内部实现和外部行为分隔开来,
面向对象程序设计方法的一个重要特点就是 封装性。封装性,指两方面含义, 1)将有关的数据和操作代码(函数)封装在一个对象中,形成一个基本单位,各个对对象之间相互独立,互不干扰;2)将对象中某些部分对外隐蔽,即隐藏部分细节(如下面例子的狗是怎么叫的),只留下函数名(吠叫)做接口,外部就可以通过函数名来调用这些函数来实现某些行为(如使用吠叫()函数来让狗叫)
抽象的作用是表示同一类事物的本质
类是对象的抽象,对象是类的特例,或者说是类的具体表现形式

继承性(Inheritance)是指,在某种情况下,一个类会有“子类”。子类比原本的类(称为父类)要更加具体化,例如,“狗”这个类可能会有它的子类“牧羊犬”和“吉娃娃犬”。在这种情况下,“莱丝”可能就是牧羊犬的一个实例。子类会继承父类的属性和行为,并且也可包含它们自己的。我们假设“狗”这个类有一个方法叫做“吠叫()”和一个属性叫做“毛皮颜色”。它的子类(前例中的牧羊犬和吉娃娃犬)会继承这些成员。这意味着程序员只需要将相同的代码写一次。详细看下面介绍

多态(Polymorphism)是指由继承而产生的相关的不同的类,其对象对同一消息会做出不同的响应。

以下来自 维基百科

类(Class)定义了一件事物的 抽象特点。通常来说,类定义了事物的 属性 和它可以做到的(它的 行为)。举例来说,“狗”这个类会包含狗的一切基础特征,例如它的孕育、毛皮颜色和吠叫的能力。类可以为程序提供模版和结构。一个类的 方法属性 被称为 “成员”。 我们来看一段伪代码,旁边是C++的语法形式::

类 狗         class Dog

开始         {

公有成员:     public:

  吠叫():       吠叫();

私有成员:     private:

  孕育:           孕育;
  毛皮颜色:       毛皮颜色;

结束          };

在这串代码中,我们声明了一个类,这个类具有一些狗的基本特征。

对象

对象(Object)是类的实例。例如,“狗”这个类列举狗的特点,从而使这个类定义了世界上所有的狗。而莱丝这个 对象 则是一条 具体 的狗,它的属性也是 具体 的。狗有皮毛颜色,而莱丝的皮毛颜色是棕白色的。因此,莱丝就是狗这个 类的一个实例。一个 具体对象属性的值被称作它的“状态” 。(系统给对象分配内存空间,而不会给类分配内存空间,这很好理解,类是抽象的系统不可能给抽象的东西分配空间,对象是具体的) 假设我们已经在上面定义了狗这个类,我们就可以用这个类来定义对象::

                        int main()
                        {
定义莱丝是狗                    Dog 莱丝;
莱丝.毛皮颜色:=棕白色           莱丝.毛皮颜色;  //注意符号“.” ,不要少了
莱丝.吠叫()                     莱丝.吠叫();     //注意符号“.” ,不要少了
                            }

书上内容:

作为 对象 时要有两个要素:1 属性 (毛皮颜色) 和 行为 (吠叫) 。 每个对象都是由 数据 (毛皮颜色)和 函数 (吠叫(),即操作代码) 这两个部分组成的。 数据 体现了前面提到的 “属性”, 函数 是用来对 数据 进行操作的,以便实现某些功能(如吠叫 行为 )。在程序设计中称为方法。

方法

方法(Method,可看成能力)是定义一个类可以做的,但不一定会去做的事。作为一条狗,莱丝是会叫的,因此“吠叫()”就是它的一个方法。与此同时,它可能还会有其它方法,例如“坐下()”,或者“吃()”。 对一个具体对象的方法进行调用并不影响其它对象,正如所有的狗都会叫,但是你让一条狗叫不代表所有的狗都叫。 如下例::

              int main()
              {
定义莱丝是狗           Dog 莱丝;
定义泰尔是狗           Dog 泰尔;
莱丝.吠叫()            莱丝.吠叫();
                 return 0;
                  }

泰尔会叫—,但没有吠叫,因为这里的吠叫只是对对象“莱丝”进行的, 换句话说你没有让泰尔,所以泰尔不会吠叫。

消息

一个对象通过接受消息、处理消息、传出消息或使用其他类的方法来实现一定功能,这叫做消息传递机制(Message Passing)。

书上内容: 为了让莱丝吠叫,你必须对莱丝下达命令,这个命令就叫消息。调用对象(莱丝)中的函数(如 吠叫() ),就是向该对象(莱丝)传送一个消息,要求该对象(莱丝)实现某个行为(吠叫)。

继承

继承性(Inheritance)是指,在某种情况下,一个类会有“子类”。子类比原本的类(称为父类)要更加具体化,例如,“狗”这个类可能会有它的子类“牧羊犬”和“吉娃娃犬”。在这种情况下,“莱丝”可能就是牧羊犬的一个实例。子类会继承父类的属性和行为,并且也可包含它们自己的。我们假设“狗”这个类有一个方法叫做“吠叫()”和一个属性叫做“毛皮颜色”。它的子类(前例中的牧羊犬和吉娃娃犬)会继承这些成员。这意味着程序员只需要将相同的代码写一次。 在伪代码中我们可以这样写::

类牧羊犬:继承狗                                         class 牧羊犬: public Dog
                                                       {
定义莱丝是牧羊犬                                               牧羊犬   莱丝;
                                                       };

                                                       int main()
                                                       {
莱丝.吠叫()    /* 注意这里调用的是狗这个类的吠叫方法。 */      莱丝.吠叫();
                                                         return 0;
                                                       }

回到前面的例子,“牧羊犬”这个类可以继承“毛皮颜色”这个属性,并指定其为棕白色。而“吉娃娃犬”则可以继承“吠叫()”这个方法,并指定它的音调高于平常。子类也可以加入新的成员,例如,“吉娃娃犬”这个类可以加入一个方法叫做“颤抖()”。设若用“牧羊犬”这个类定义了一个实例“莱丝”,那么莱丝就不会颤抖,因为这个方法是属于吉娃娃犬的,而非牧羊犬。事实上,我们可以把继承理解为“是”。例如,莱丝“是”牧羊犬,牧羊犬“是”狗。因此,莱丝既得到了牧羊犬的属性,又继承了狗的属性。 我们来看伪代码::

 类吉娃娃犬:继承狗                                   class 吉娃娃犬: public Dog
 开始                                                {
 公有成员:                                           public:
   颤抖()                                                颤抖()
结束                                                 };

类牧羊犬:继承狗                                      class 牧羊犬: public Dog
                                                     {

                                                     };
                                                     int main()
                                                     {

定义莱丝是牧羊犬                                         牧羊犬  莱丝;
莱丝.颤抖()    /* 错误:颤抖是吉娃娃犬的成员方法。 */    莱丝.颤抖();
                                                         return 0;
                                                     }

当一个类从多个父类继承时,我们称之为“多重继承”(书本373页)。多重继承并不总是被支持的,因为它很难理解,又很难被好好使用。

封装性

具备封装性(Encapsulation)的面向对象程序设计 隐藏了某一方法的具体执行步骤 ,取而代之的是通过 消息传递机制传送消息给它 (也就是调用函数)。因此,举例来说,“狗”这个类有“吠叫()”的方法,这一方法定义了狗具体该通过什么方法吠叫。但是,莱丝的朋友蒂米并不需要知道它到底如何吠叫。 也就是说,把对象的内部实现和外部的行为分隔开来 从实例来看::

/* 一个面向过程的程序会这样写: */
定义莱丝
/*这是内部实现,定义了狗具体是怎么吠叫的,但是外部不需要知道*/
莱丝.设置音调(5)
莱丝.吸气()
莱丝.吐气()

/* 而当狗的吠叫被封装到类中,任何人都可以简单地使用: */
定义莱丝是狗
/* 外部只需要使用 吠叫() 这个函数,让狗叫就好了,至于怎么叫的就不需要知道了*/
莱丝.吠叫()

封装是通过限制只有特定类的实例可以访问这一特定类的成员,而它们通常利用接口实现消息的传入传出。举个例子,接口能确保幼犬这一特征只能被赋予狗这一类。通常来说,成员会依它们的访问权限被分为3种:公有成员、私有成员以及保护成员。

书上内容:

面向对象程序设计方法的一个重要特点就是 封装性。封装性,指两方面含义, 1)将有关的数据和操作代码(函数)封装在一个对象中,形成一个基本单位,各个对对象之间相互独立,互不干扰;2)将对象中某些部分对外隐蔽,即隐藏部分细节(如上例的狗是怎么叫的),只留下函数名(吠叫)做接口,外部就可以通过函数名来调用这些函数来实现某些行为(如使用吠叫()函数来让狗叫)

多态

多态(Polymorphism)是指由继承而产生的相关的不同的类,其对象对同一消息会做出不同的响应。举例来说,狗和鸡都有“叫()”这一方法,但是调用狗的“叫()”,狗会吠叫;调用鸡的“叫()”,鸡则会啼叫。 我们将它体现在伪代码上::

类狗                   class Dog
开始                   {
公有成员:              public:
   叫()                   叫()
   开始                   {
      吠叫()                吠叫()
   结束                   }
结束                    }

类鸡                   class 鸡
开始                   {
公有成员:              public:
   叫()                   叫()
   开始                   {
      啼叫()                啼叫()
   结束                   }
结束                    }
                      int main()
                      {
定义莱丝是狗              Dog 莱丝;
定义鲁斯特是鸡            鸡  鲁斯特;
莱丝.叫()                 莱丝.叫();
鲁斯特.叫()               鲁斯特.叫();
                          return 0;
                      }

这样,同样是叫(也就是使用 叫() 这个函数),莱丝和鲁斯特做出的反应将大不相同。多态性的概念可以用在运算符重载上。

抽象性

抽象(Abstraction)是简化复杂的现实问题的途径,它可以为具体问题找到最恰当的类定义,并且可以在最恰当的继承级别解释问题。举例说明,莱丝在大多数时候都被当作一条狗,但是如果想要让它做牧羊犬做的事,你完全可以调用牧羊犬的方法。如果狗这个类还有动物的父类,那么你完全可以视莱丝为一个动物。

书上内容:

抽象的作用是表示同一类事物的本质。

类是对象的抽象,对象是类的特例,或者说是类的具体表现形式。

留言