下面再来看书,去理解书上说的Handler classes就简单多了,我们大概过一下。

假设我们要写一个Person类,如下:

 1 class Person
 2 {
 3 private:
 4     string name;
 5     MyDate birthday;
 6     MyAddress address;
 7
 8 public:
 9     // fallows functions
10     // ...
11 };

这个Person类里面包含有人的名字,人的生日以及地址,还有一些没有列出来的方法。注意到这里用到了string(它不是一个class,只是一个typedef,大多数情况下,我们认为它不会有任何改变),以及自定义的类MyDate与MyAddress,一种常见的做法是采用include头文件,像这样:

1 #include <string>
2 #include "MyDate.h"
3 #include "MyAddress.h"

在MyDate.h里面写好日期类相关的成员变量与方法,而在MyAddress.h里面写好地址类相关的成员变量与方法。但如果此后要往MyDate类或者MyAddresss类添加成员变量,那么不仅仅所有用到MyDate或者MyAddress对象的文件需要重新编译,而且所有用到Person对象的文件也需要重编译,一个小改动竟然会牵涉到这么多的地方!

可以把问题归结为“C++并没有把将接口从实现中分离这件事做好”,因为包含头文件的做法很直观很方便,用的人也很普遍,而C++并没有对这种做法加以限制。

如果要把编译的依赖性降低,就要换一种思路来处理,不能出现定义式,只能出现声明式,代价是增加代码的复杂度以及性能上的一些损失。

书上提到了两种方法,第一种是采用Handler Classes(用指针指向真正实现的方法),第二种是Interface Classes(抽象基类)。

对于第一种Handler Class,一句话,就是.h里面不包含类的自定义头文件,用“class 类名”的声明方式进行代替(也要把相应的成员变量替换成指针或引用的形式),在.cpp文件里面包含类的自定义头文件去实现具体的方法。改造之后的程序看起来是这样子的:

 1 // Person.h
 2 #include <string>
 3 using namespace std;
 4
 5 class PersonImp;
 6
 7 class Person
 8 {
 9 private:
10     //string Name;
11     //MyDate Birthday;
12     //MyAddress Address;
13     PersonImp* MemberImp;
14
15 public:
16     string GetName() const;
17     string GetBirthday() const;
18     string GetAddress() const;
19     // follows functions
20     // ...
21 };

 1 // Person.cpp
 2 #include "PersonImp.h"
 3 #include "Person.h"
 4
 5 string Person::GetName() const
 6 {
 7     return MemberImp->GetName();
 8 }
 9 string Person::GetBirthday() const
10 {
11     return MemberImp->GetName();
12 }
13 string Person::GetAddress() const
14 {
15     return MemberImp->GetAddress();
16 }

 1 // PersonImp.h
 2 #ifndef PersonImp_H
 3 #define PersonImp_H
 4
 5 #include <string>
 6 #include "MyAddress.h"
 7 #include "MyDate.h"
 8 using namespace std;
 9
10 class PersonImp
11 {
12 private:
13     string Name;
14     MyAddress Address;
15     MyDate Birthday;
16
17 public:
18     string GetName() const
19     {
20         return Name;
21     }
22
23     string GetAddress() const
24     {
25         return Address.ToString();
26     }
27
28     string GetBirthday() const
29     {
30         return Birthday.ToString();
31     }
32 };
33
34 #endif /* PersonImp_H */

 1 // MyDate.h
 2 #ifndef MY_DATE_H
 3 #define MY_DATE_H
 4
 5 #include <string>
 6 using namespace std;
 7
 8 class MyDate
 9 {
10 private:
11     int Year;
12     int Month;
13     int DayOfMonth;
14
15 public:
16     string ToString() const;
17 }
18 #endif /* MY_DATE_H */

 1 // MyAddress.h
 2 #ifndef MY_ADDRESS_H
 3 #define MY_ADDRESS_H
 4
 5 #include <string>
 6 using namespace std;
 7
 8 class MyAddress
 9 {
10 private:
11     string Country;
12     string Province;
13     string City;
14     string Street;
15
16 public:
17     string ToString() const;
18 };
19
20 #endif /* MY_ADDRESS_H */

这里有一点要说一下,在Person.h里面并没有使用MyDate*和MyAddress*,而是用了PersonImp*,由PersonImp里面包含MyDate与MyAddress,这样做的好处就是方便统一化管理,它要求PersonImp里面的方法与Person的方法是一致的。以后Person添加成员变量,可以直接在PersonImp中进行添加了,从而起到了隔离和隐藏的作用,因为客户端代码大量使用的将是Person,而不必关心PersonImp,用于幕后实现的PersonImp只面向于软件开发者而不是使用者。

书上是用shared_ptr来管理PersonImp的,使资源管理上更加科学与合理。

另外,书上也提倡把class x; class xx; class xxx;的声明放至一个名为”xxxfwd.h”的头文件里,比如”datefwd.h”,这个头文件里面只有声明式,而没有具体的类细节。也就是说,对于某个类,比如MyDate,应该分出三个文件,一个是datefwd.h,里面是一些用到的外来的class声明式;一个是MyDate.h里面是MyDate类的结构声明;一个是MyDate.cpp,它与MyDate.h配对,给出具体的实现细节。

转载于:https://www.cnblogs.com/jerry19880126/p/3551839.html

读书笔记_Effective_C++_条款三十一:将文件间的编译依存关系降至最低(第二部分)...相关推荐

  1. Effective C++笔记_条款31将文件间的编译依存关系降至最低

    Effective C++笔记_条款31将文件间的编译依存关系降至最低 这个章节,读了两遍还是不是很清楚,有一种没法和作者沟通的感觉,看来我还是一个C++的初学者呀.好吧,不多说了,回归主题,今天的笔 ...

  2. 读书笔记_Effective_C++_条款十九:设计class犹如设计type

    这里初看到"class"和"type",感觉他们是说的是同一样东西,但仔细读了一下,两者在文中还是有区别的.class侧重于自定义的类,而type侧重于系统预定 ...

  3. 读书笔记_Effective_C++_条款七:为多态基类声明virtual析构函数

    严格来说,多态分为编译时多态和运行时多态,编译时多态是函数的重载,而运行时多态则是迟绑定技术,即根据基类指针或引用的实际指向来决定采取何种行动,一般来说,多态特指运行时多态.下面我们来举有关C++多态 ...

  4. 读书笔记_Effective_C++_条款二十四: 若所有参数皆需类型转换,请为此采用non-member函数...

    class A { private:int a; public:A(int x) :a(x){}A operator*(const A& x){return A(a*x.a);} };int ...

  5. Effective C++ 阅读笔记(一)透彻了解inline以及降低编译依存关系

    inline内敛 1.类似于C中的#define 在C++中,提供了inline函数来代替C中的宏定义.(通常可以使用const来代替单纯变量的宏定义,它可以提供类型检查.对于形似函数的宏,最好改用i ...

  6. Python编程基础:第三十一节 文件读取Read a File

    第三十一节 文件读取Read a File 前言 实践 前言 当我们检测到文件之后就可以读取其中的内容,读取所用到的函数是read(). 实践 我们依然以上一节的lyric.txt为例展示如何读取文件 ...

  7. 读书笔记:汇编语言 第三版 王爽 清华出版社 前言 章一 章二 章三 章四 章五

    汇编语言 第三版 王爽 清华出版社文档记录创建 2020年8月9日15:21:11初稿完成 2020年9月5日15:38:22前言汇编语言,CPU提供的机器指令的助记符的集合不同处理器,机器指令可能不 ...

  8. oracle体系三大文件,oracle 体系_第三章控制文件

    第三章 控制文件 1.功能特点 记录数据库当前的物理状态 维护数据库的一致性,是一个二进制的小文件 在mount阶段被读取,记录rman备份的元数据 查看database控制文件的位置 Show pa ...

  9. 360文件粉碎机_中山三乡资料文件销毁粉碎销毁资料文件公司一览表

    中山三乡资料文件销毁粉碎销毁资料文件公司一览表 安排搬运工作人员及运输车辆上门收取销毁物品,将需销毁的物品装上运输车辆,并进行拍照.车箱粘贴封条等工作.第五步:客户可安排工作人员,跟我公司销毁运输车辆 ...

最新文章

  1. 图解Transformer:Attention Is All You Need
  2. 如何做一款成功的APP应用
  3. JUnit测试框架的使用经验分享
  4. 图论 —— 最大团问题
  5. 字符设备驱动程序的使用
  6. 基于深度学习的搜索、推荐、广告系统最全最新论文分享
  7. Android 中文API (38) —— Spinner
  8. python安装方法_听说你安装Python包很慢,试试这个方法
  9. matlab altera视频,Altera 官网中文视频教程 下载地址
  10. JSP九大内置对象总结
  11. 差分管电路图_最简单的单差分OCL功放电路图(四款单差分OCL功放电路设计原理图详解)...
  12. Oracle 11gR2 RAC 修改监听端口号
  13. Kotlin-协程Coroutines-组合suspending暂停函数
  14. 一个案例深入Python中的__new__和__init__
  15. LaTeX模板——英文写作
  16. Verilog语言快速入门(一)
  17. 使用Navicat自带的导出与使用查询方式的导出区别
  18. Selenium 导航操作 Navigating
  19. python效验车辆VIN码小程序
  20. python进阶day4

热门文章

  1. PPT快速制作精美3D柱状图
  2. 10. http 的一些说明及分析工具
  3. CLR Via CSharp读书笔记(14):字符、字符串和文本处理
  4. what is your judgement basis?
  5. research proposal under dr. wang
  6. 2108889队2021年数学建模美赛C题花絮视频!
  7. 要承认我们换电脑频繁的效率并不是很高
  8. 我的性格是外向型,解决问题导向的
  9. 【转】early-z、z-culling、hi-z、z-perpass
  10. 更改hostname后vnc无法进入图形界面