type
status
date
slug
summary
tags
category
icon
password
设计
现在需要让你设计两个类:狗和猫。
类里要有狗或猫的一些属性,比如名字、颜色、体重、年龄;还要有狗或猫的一些行为,比如叫等。
第一个版本
我们可以很轻易设计出狗和猫的类:
抽取共同点
我们发现这两个类有一些共同的成员变量(属性)、成员函数(功能)。而如果让我们再去定义其他的动物类,比如🐂,🐖,🐏等等,这些共同点还要一遍一遍地重写。
可以把这些共同之处抽取出来,抽象成一个动物类。动物类中定义猫和狗的共同属性。
属性名字、颜色、体重、年龄和行为叫是共同的,把它们放在动物类中。而属性奔跑速度、行为摇尾巴是狗独有的,行为捉老鼠是猫独有的,不用放在动物类中。
然后我们来继承动物类。
狗:
新的狗类继承了父类所有的public属性(name,weight,color,age)和方法(speak())。只需要定义狗独有的属性speed即可。这样定义和第一版的狗类其实算一样的,但可以少写很多相同的代码。
方法speak由子类具体实现,这里我们实现了狗的叫声。再狗类中加入狗独有的摇尾巴方法。
狗类的构造函数和第一版的也没什么区别,但是这里可以把共有的属性(name,weight,color,age)直接交给父类的构造函数来初始化,实际上和第一版的构造函数结果是一样的。
猫:
这里实现了猫的speak方法,还新加入了猫独有的捉老鼠方法。猫类的构造函数和父类完全一致,直接调用父类即可。
现在我们的设计架构如下图,三角形箭头代表继承关系。
使用
现在我们用这两个类生成一堆具体的猫猫狗狗:
或者用指针的方式生成:
Cat类只是对猫的抽象定义,这里tom、mimi都是类Cat的一个实例(对象)。生成具体对象的过程也叫实例化。
现在你想设计一个铲屎官类,但是只能养一只猫或者一只狗。你现在还不能决定是猫还是狗,所以干脆直接先为铲屎官类定义一个动物的指针:
等你决定要养什么了,再让这个指针指向具体的猫或狗。
为铲屎官设计逗宠物叫的方法:
好现在铲屎官类设计完了,但具体是猫的铲屎官还是狗的铲屎官就要等生成Chanshiguan对象的时候再决定了。
面向对象(Object-oriented)
现在再说说啥叫面向对象。
封装
第一版设计里,我们一开始把狗和猫的属性、行为分别放在狗类和猫类里。这是为了:
- 防止变量被外部污染
- 防止之后每次定义一个具体的猫狗都要重写所有的属性代码
这里就是面向对象编程的第一个特点:封装。面向对象思想把万物看作对象,万物都是由属性和行为来定义的。
继承
下一版设计里,我们发下猫狗有很多共同的属性和方法。每次定义一个新的动物类都要重写一遍这些共同方法,干脆把这些动物都有的共同点抽取出来。
我们设计了一个动物类Animal,让各种类型的动物来继承Animal。这样共同的属性、方法都不用再写一遍了。这里就是面向对象编程的第二个特点:继承。
多态
设计一个动物父类,让各种动物都继承它,最显然的优点当然是减少代码重复。但仅仅是少写代码这点优势吗?
在定义铲屎官类的时候,我们看到甭管什么动物,只需要定义一个Animal类型的指针就可以管理具体动物对象。只要用animal→speak();就可以调用动物叫的方法,而不必管是什么类型的动物。具体是汪汪还是喵喵,等代码跑起来让系统自己决定就好了。这里就是面向对象编程的第三个特点:多态,即同一代码在运行时的不同行为。
has-a与is-a
现在我们的系统整体架构如上图。
铲屎官类里面包含有一个动物类,他们包含关系:A Chanshiguan has an Animal。
而猫、狗是继承了动物类,猫、狗是动物,他们的关系:A Cat or Dog is an Animal。
这就是面向对象编程里最经典的两种关系:has-a与is-a。
- 作者:HSZTY
- 链接:hszty.cn/article/cpp-tutorial-inherit
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。