`
BlogDown
  • 浏览: 213862 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

C++编程规范---第10章 类的继承与组合

 
阅读更多

对象(Object)是类(Class)的一个实例(Instance)。如果将对象比作房子,那么类就是房子的设计图纸。所以面向对象设计的重点是类的设计,而不是对象的设计。

对于C++程序而言,设计孤立的类是比较容易的,难的是正确设计基类及其派生类。本章仅仅论述“继承”(Inheritance)和“组合”(Composition)的概念。

注意,当前面向对象技术的应用热点是COMCORBA,这些内容超出了C++教材的范畴,请阅读COMCORBA相关论著。

继承

如果A是基类,BA的派生类,那么B将继承A的数据和函数。例如:

class A

{

public:

voidFunc1(void);

voidFunc2(void);

};

class B : public A

{

public:

voidFunc3(void);

voidFunc4(void);

};

main()

{

Bb;

b.Func1();// BA继承了函数Func1

b.Func2();// BA继承了函数Func2

b.Func3();

b.Func4();

}

这个简单的示例程序说明了一个事实:C++的“继承”特性可以提高程序的可复用性。正因为“继承”太有用、太容易用,才要防止乱用“继承”。我们应当给“继承”立一些使用规则。

l【规则10-1-1如果类A和类B毫不相关,不可以为了使B的功能更多些而让B继承A的功能和属性。不要觉得“白吃白不吃”,让一个好端端的健壮青年无缘无故地吃人参补身体。

l【规则10-1-2若在逻辑上BA的“一种”(a kind of),则允许B继承A的功能和属性。例如男人(Man)是人(Human)的一种,男孩(Boy)是男人的一种。那么类Man可以从类Human派生,类Boy可以从类Man派生。

class Human

{

};

class Man : public Human

{

};

class Boy : public Man

{

};

u注意事项

【规则10-1-2看起来很简单,但是实际应用时可能会有意外,继承的概念在程序世界与现实世界并不完全相同。

例如从生物学角度讲,鸵鸟(Ostrich)是鸟(Bird)的一种,按理说类Ostrich应该可以从类Bird派生。但是鸵鸟不能飞,那么Ostrich::Fly是什么东西?

class Bird

{

public:

virtual void Fly(void);

};

class Ostrich : public Bird

{

};

例如从数学角度讲,圆(Circle)是一种特殊的椭圆(Ellipse),按理说类Circle应该可以从类Ellipse派生。但是椭圆有长轴和短轴,如果圆继承了椭圆的长轴和短轴,岂非画蛇添足?

所以更加严格的继承规则应当是:若在逻辑上BA的“一种”,并且A的所有功能和属性对B而言都有意义,则允许B继承A的功能和属性。

10.2组合

l【规则10-2-1若在逻辑上AB的“一部分”(a part of),则不允许BA派生,而是要用A和其它东西组合出B

例如眼(Eye)、鼻(Nose)、口(Mouth)、耳(Ear)是头(Head)的一部分,所以类Head应该由类EyeNoseMouthEar组合而成,不是派生而成。如示例10-2-1所示。

class Eye

{
public:

voidLook(void);

};

class Nose

{
public:

voidSmell(void);

};

class Mouth

{
public:

voidEat(void);

};

class Ear

{
public:

voidListen(void);

};

//正确的设计,虽然代码冗长。

class Head

{

public:

voidLook(void){m_eye.Look();}

voidSmell(void){m_nose.Smell();}

voidEat(void){m_mouth.Eat();}

voidListen(void){m_ear.Listen();}

private:

Eyem_eye;

Nosem_nose;

Mouthm_mouth;

Earm_ear;

};

示例10-2-1HeadEyeNoseMouthEar组合而成

如果允许HeadEyeNoseMouthEar派生而成,那么Head将自动具有LookSmellEatListen这些功能。示例10-2-2十分简短并且运行正确,但是这种设计方法却是不对的。

//功能正确并且代码简洁,但是设计方法不对。

class Head : public Eye, public Nose, public Mouth, public Ear

{

};

示例10-2-2HeadEyeNoseMouthEar派生而成

一只公鸡使劲地追打一只刚下了蛋的母鸡,你知道为什么吗?

因为母鸡下了鸭蛋。

很多程序员经不起“继承”的诱惑而犯下设计错误。“运行正确”的程序不见得是高质量的程序,此处就是一个例证。


对象(Object)是类(Class)的一个实例(Instance)。如果将对象比作房子,那么类就是房子的设计图纸。所以面向对象设计的重点是类的设计,而不是对象的设计。

对于C++程序而言,设计孤立的类是比较容易的,难的是正确设计基类及其派生类。本章仅仅论述“继承”(Inheritance)和“组合”(Composition)的概念。

注意,当前面向对象技术的应用热点是COMCORBA,这些内容超出了C++教材的范畴,请阅读COMCORBA相关论著。

继承

如果A是基类,BA的派生类,那么B将继承A的数据和函数。例如:

class A

{

public:

voidFunc1(void);

voidFunc2(void);

};

class B : public A

{

public:

voidFunc3(void);

voidFunc4(void);

};

main()

{

Bb;

b.Func1();// BA继承了函数Func1

b.Func2();// BA继承了函数Func2

b.Func3();

b.Func4();

}

这个简单的示例程序说明了一个事实:C++的“继承”特性可以提高程序的可复用性。正因为“继承”太有用、太容易用,才要防止乱用“继承”。我们应当给“继承”立一些使用规则。

l【规则10-1-1如果类A和类B毫不相关,不可以为了使B的功能更多些而让B继承A的功能和属性。不要觉得“白吃白不吃”,让一个好端端的健壮青年无缘无故地吃人参补身体。

l【规则10-1-2若在逻辑上BA的“一种”(a kind of),则允许B继承A的功能和属性。例如男人(Man)是人(Human)的一种,男孩(Boy)是男人的一种。那么类Man可以从类Human派生,类Boy可以从类Man派生。

class Human

{

};

class Man : public Human

{

};

class Boy : public Man

{

};

u注意事项

【规则10-1-2看起来很简单,但是实际应用时可能会有意外,继承的概念在程序世界与现实世界并不完全相同。

例如从生物学角度讲,鸵鸟(Ostrich)是鸟(Bird)的一种,按理说类Ostrich应该可以从类Bird派生。但是鸵鸟不能飞,那么Ostrich::Fly是什么东西?

class Bird

{

public:

virtual void Fly(void);

};

class Ostrich : public Bird

{

};

例如从数学角度讲,圆(Circle)是一种特殊的椭圆(Ellipse),按理说类Circle应该可以从类Ellipse派生。但是椭圆有长轴和短轴,如果圆继承了椭圆的长轴和短轴,岂非画蛇添足?

所以更加严格的继承规则应当是:若在逻辑上BA的“一种”,并且A的所有功能和属性对B而言都有意义,则允许B继承A的功能和属性。

10.2组合

l【规则10-2-1若在逻辑上AB的“一部分”(a part of),则不允许BA派生,而是要用A和其它东西组合出B

例如眼(Eye)、鼻(Nose)、口(Mouth)、耳(Ear)是头(Head)的一部分,所以类Head应该由类EyeNoseMouthEar组合而成,不是派生而成。如示例10-2-1所示。

class Eye

{
public:

voidLook(void);

};

class Nose

{
public:

voidSmell(void);

};

class Mouth

{
public:

voidEat(void);

};

class Ear

{
public:

voidListen(void);

};

//正确的设计,虽然代码冗长。

class Head

{

public:

voidLook(void){m_eye.Look();}

voidSmell(void){m_nose.Smell();}

voidEat(void){m_mouth.Eat();}

voidListen(void){m_ear.Listen();}

private:

Eyem_eye;

Nosem_nose;

Mouthm_mouth;

Earm_ear;

};

示例10-2-1HeadEyeNoseMouthEar组合而成

如果允许HeadEyeNoseMouthEar派生而成,那么Head将自动具有LookSmellEatListen这些功能。示例10-2-2十分简短并且运行正确,但是这种设计方法却是不对的。

//功能正确并且代码简洁,但是设计方法不对。

class Head : public Eye, public Nose, public Mouth, public Ear

{

};

示例10-2-2HeadEyeNoseMouthEar派生而成

一只公鸡使劲地追打一只刚下了蛋的母鸡,你知道为什么吗?

因为母鸡下了鸭蛋。

很多程序员经不起“继承”的诱惑而犯下设计错误。“运行正确”的程序不见得是高质量的程序,此处就是一个例证。

分享到:
评论

相关推荐

    C++编程规范101条规则、准则与最佳实践PDF.rar

    第10条 尽量减少全局和共享数据 19 第11条 隐藏信息 20 第12条 懂得何时和如何进行并发性编程 21 第13条 确保资源为对象所拥有。使用显式的RAII和智能指针 24 编程风格 27 第14条 宁要编译时和连接...

    高质量C/C++编程指南

    帮助我们写出漂亮、规范的代码 第1 章 文件结构 第2 章 程序的版式 第3 章 命名规则 第4 章 表达式和基本语句 第5 章 常量 第6 章 函数设计 第7 章 内存管理 ...第10 章 类的继承与组合 第11 章 其它编程经验

    C++ Qt设计模式(第2版)

    第10章 主窗口和动作 225 第11章 范型和容器 246 第12章 元对象,属性和反射编程 262 第13章 模型和视图 277 第14章 验证和正则表达式 302 第15章 XML解析 318 第16章 更多的设计模式 335 第17章 并发 353 ...

    C/C++ 编码风格 编码规范

    软件质量是被大多数程序员挂在嘴上而不是放在心上的东西! 除了完全外行和真正的编程高手外,初读本书,你最先的感受将是惊慌:“哇!我以 ...第10章 类的继承与组合 第11章 其他编程经验 参考文献

    C++ Primer第四版【中文高清扫描版】.pdf

    第10章 关联容器 305 10.1 引言:pair类型 306 10.2 关联容器 308 10.3 map类型 309 10.3.1 map对象的定义 309 10.3.2 map定义的类型 310 10.3.3 给map添加元素 311 10.3.4 使用下标访问map对象 311 10.3.5 map::...

    [程序员成长课堂:C.标准教程].陈国建等.扫描版.pdf

    C++是在C语言的基础上发展而来的,但C++又可视为是一门...第10章 面向对象程序设计 213 第四篇 C++编程实践 第11章 教学管理系统的C++实现 260 附录A Visual C++菜单中文注释 299 附录B Visual C++操作技巧小代码 302

    C++Primer(第5版 )中文版(美)李普曼等著.part2.rar

     第10章 泛型算法 335  10.1 概述 336  10.2 初识泛型算法 338  10.2.1 只读算法 338  10.2.2 写容器元素的算法 339  10.2.3 重排容器元素的算法 342  10.3 定制操作 344  10.3.1 向算法传递函数 344  ...

    C++数据抽象和问题求解(第6版).[美]Frank M. Carrano(带详细书签).pdf

    第10章 算法的效率 283 10.1 什么是好的解决方案 284 10.2 测量算法的效率 285 10.2.1 算法的执行时间 286 10.2.2 算法增长率 287 10.2.3 分析与大O表示法 288 10.2.4 正确分析问题 291 10.2.5 查找算法的...

    C++ Primer中文版(第5版)李普曼 等著 pdf 1/3

     第10章 泛型算法 335  10.1 概述 336  10.2 初识泛型算法 338  10.2.1 只读算法 338  10.2.2 写容器元素的算法 339  10.2.3 重排容器元素的算法 342  10.3 定制操作 344  10.3.1 向算法传递函数 344  ...

    C++ Qt设计模式源代码

    全书共分四个部分:第一部分介绍C++、UML、Qt、模型-视图、SQL、XML、设计模式等基础知识,目的是为零基础的C++初学者铺垫一条学习面向对象编程的快捷之路;第二部分讲解内存访问、继承等重要的C++特性,是前一部分...

    新版Android开发教程.rar

    ----------------------------------- Android 编程基础 1 封面----------------------------------- Android 编程基础 2 开放手机联盟 --Open --Open --Open --Open Handset Handset Handset Handset Alliance ...

    C语言规范文档

    第1章 文件结构 第2章 程序的版式 第3章 命名规则 第4章 表达式和基本语句 第5章 常量 第6章 函数设计 第7章 内存管理 第8章 C++函数的高级特性 第9章 类的构造函数、析构...第10章 类的继承与组合 第11章 其它编程经验

    Thinking in Java 中文第四版+习题答案

    第10章 Java IO系统 10.1 输入和输出 10.1.1 InputStream的类型 10.1.2 OutputStream的类型 10.2 增添属性和有用的接口 10.2.1 通过FilterInputStream从InputStream里读入数据 10.2.2 通过FilterOutputStream向...

    C/C++程序员面试指南.杨国祥(带详细书签).pdf

    第10章 数据结构 10.1 链表 面试题1:链表和数组有什么区别 面试题2:寻找单链表中间结点 面试题3:怎样把一个单链表反序 10.2 单循环链表 面试题4:根据需求建立一个单向循环链表 面试题5:检测一个较大的单向链表...

    JAVA_Thinking in Java(中文版 由yyc,spirit整理).chm

    第10章 Java IO系统 10.1 输入和输出 10.1.1 InputStream的类型 10.1.2 OutputStream的类型 10.2 增添属性和有用的接口 10.2.1 通过FilterInputStream从InputStream里读入数据 10.2.2 通过FilterOutputStream向...

    Thinking in Java(中文版 由yyc,spirit整理).chm

    第10章 Java IO系统 10.1 输入和输出 10.1.1 InputStream的类型 10.1.2 OutputStream的类型 10.2 增添属性和有用的接口 10.2.1 通过FilterInputStream从InputStream里读入数据 10.2.2 通过FilterOutputStream向...

    java 编程入门思考

    第10章 Java IO系统 10.1 输入和输出 10.1.1 InputStream的类型 10.1.2 OutputStream的类型 10.2 增添属性和有用的接口 10.2.1 通过FilterInputStream从InputStream里读入数据 10.2.2 通过FilterOutputStream向...

    易语言程序免安装版下载

     支持静态链接其它编程语言(如C/C++、汇编等)编译生成的静态库(.LIB或.OBJ),但仅限于COFF格式,支持cdecl和stdcall两种函数调用约定。  使用说明如下:函数声明和调用方法与DLL命令一致;“库文件名”以.lib...

    浙江大学--软件工程.rar

    6.1.2 继承与组合 6.1.3 虚函数与多态 6.2 良好的编程风格 6.2.1 命名约定 6.2.2 使用断言 6.2.3 new、delete与指针 6.2.4 使用const 6.2.5 其它建议 6.3 小结 第七章 测试与改错 7.1 对测试的理解 7.1.1 测试的...

Global site tag (gtag.js) - Google Analytics