type
status
date
slug
summary
tags
category
icon
password

设计

 
现在需要让你设计两个类:狗和猫。
 
类里要有狗或猫的一些属性,比如名字、颜色体重、年龄;还要有狗或猫的一些行为,比如等。
 

第一个版本

我们可以很轻易设计出狗和猫的类:
 
 

抽取共同点

我们发现这两个类有一些共同的成员变量(属性)、成员函数(功能)。而如果让我们再去定义其他的动物类,比如🐂,🐖,🐏等等,这些共同点还要一遍一遍地重写。
 
可以把这些共同之处抽取出来,抽象成一个动物类。动物类中定义猫和狗的共同属性。
 
属性名字、颜色体重、年龄和行为是共同的,把它们放在动物类中。而属性奔跑速度、行为摇尾巴是狗独有的,行为捉老鼠是猫独有的,不用放在动物类中。
 
 
然后我们来继承动物类。
狗:
新的狗类继承了父类所有的public属性(name,weight,color,age)和方法(speak())。只需要定义狗独有的属性speed即可。这样定义和第一版的狗类其实算一样的,但可以少写很多相同的代码。
 
方法speak由子类具体实现,这里我们实现了狗的叫声。再狗类中加入狗独有的摇尾巴方法。
 
狗类的构造函数和第一版的也没什么区别,但是这里可以把共有的属性(name,weight,color,age)直接交给父类的构造函数来初始化,实际上和第一版的构造函数结果是一样的。
 
猫:
这里实现了猫的speak方法,还新加入了猫独有的捉老鼠方法。猫类的构造函数和父类完全一致,直接调用父类即可。
 
现在我们的设计架构如下图,三角形箭头代表继承关系。
notion image
 

使用

现在我们用这两个类生成一堆具体的猫猫狗狗:
或者用指针的方式生成:
Cat类只是对猫的抽象定义,这里tom、mimi都是类Cat的一个实例(对象)。生成具体对象的过程也叫实例化
 
现在你想设计一个铲屎官类,但是只能养一只猫或者一只狗。你现在还不能决定是猫还是狗,所以干脆直接先为铲屎官类定义一个动物的指针:
等你决定要养什么了,再让这个指针指向具体的猫或狗。
 
为铲屎官设计逗宠物叫的方法:
 
好现在铲屎官类设计完了,但具体是猫的铲屎官还是狗的铲屎官就要等生成Chanshiguan对象的时候再决定了。
 
 

面向对象(Object-oriented)

现在再说说啥叫面向对象。

封装

第一版设计里,我们一开始把狗和猫的属性、行为分别放在狗类和猫类里。这是为了:
  • 防止变量被外部污染
  • 防止之后每次定义一个具体的猫狗都要重写所有的属性代码
这里就是面向对象编程的第一个特点:封装。面向对象思想把万物看作对象,万物都是由属性和行为来定义的。
 

继承

下一版设计里,我们发下猫狗有很多共同的属性和方法。每次定义一个新的动物类都要重写一遍这些共同方法,干脆把这些动物都有的共同点抽取出来。
 
我们设计了一个动物类Animal,让各种类型的动物来继承Animal。这样共同的属性、方法都不用再写一遍了。这里就是面向对象编程的第二个特点:继承
 

多态

设计一个动物父类,让各种动物都继承它,最显然的优点当然是减少代码重复。但仅仅是少写代码这点优势吗?
 
在定义铲屎官类的时候,我们看到甭管什么动物,只需要定义一个Animal类型的指针就可以管理具体动物对象。只要用animal→speak();就可以调用动物叫的方法,而不必管是什么类型的动物。具体是汪汪还是喵喵,等代码跑起来让系统自己决定就好了。这里就是面向对象编程的第三个特点:多态,即同一代码在运行时的不同行为。
 

has-a与is-a

notion image
现在我们的系统整体架构如上图。
 
铲屎官类里面包含有一个动物类,他们包含关系:A Chanshiguan has an Animal。
 
而猫、狗是继承了动物类,猫、狗动物,他们的关系:A Cat or Dog is an Animal。
 
这就是面向对象编程里最经典的两种关系:has-ais-a
 
速通C++:类定义与实例化速通C++:命名空间