effective C++笔记之条款34: 将文件间的编译依赖性降至最低

原创 2012年03月24日 15:08:25

1.    先看如下函数:
class Person
{
public:
        Person(const sting& name, const Date& birthday,
const Address& addr, const Country& country);
        virtual ~Person();
        string name() const;
        stirng birthDate() const;
        stirng address() const;
        string nationality() const;
    private:
        string name_;   //实现细节
        Date birthday_;  //实现细节
        Address address_;  //实现细节
        Country citizenship_; // 实现细节
    };


    Person的实现用到了一些类,即string,Date,Address和Country;Person要想被编译,就得让编译器能够访问到这些类的定义。一般是通过#include指令来提供的。但是,这样以来Person的文件和这些头文件之间就建立了编译依赖关系。所以任意一个辅助类改变了它的实现,或任一个辅助类所依赖的类改变了实现,包含Person类的文件以及任何使用了Person类的文件就必须重新编译。
2.    我们应该将一个对象的实现隐藏在指针的身后。看下面经过修改后的Person类:
//编译器还要知道这些类型名,因为Person的构造函数要用到它们
class string;  //对标准string来说这样做不对
class Date;
class Country;
class Address;
//类PersonImpl将包含Person对象的实现细节,此处只是类名的提前声明
class PersonImpl;
class Person
{
    public:
Person(const string& name, const Date& birthday,
const Address& addr, const Country& country);
        virtual ~Person();
        string name() const;
        string birthDate() const;
        string address() const;
        string nationality() const;
    private:
        PersonImpl *impl; //指向具体的实现类
};


现在Person的用户完全和string,date,address,country和person的实现细节分家了。那些类可以随意修改,而Person用户可以不需要重新编译。另外,因为看不到Person的实现细节,用户不可能写出依赖这些细节的代码。这是真正的接口和实现的分离。
3.    只要有可能,尽量让头文件不要依赖于别的文件;如果不可能,就借助于类的声明,不要依靠类的定义。其他一切方法都源于这一简单的设计思想。
4.    如果可以使用对象的引用和指针,就要避免使用对象本身。定义某个类型的引用和指针只会涉及到这个类型的声明,定义此类型的对象则需要类型定义的参与。

5.    尽可能使用类的声明,而不用类的定义。因为在声明一个函数时,如果用到某个类,是绝对不需要这个类的定义的,即使函数是通过传值来传递和返回这个类的。如下所示:

class Date;
Date returnADate();  //正确,不需要Date的定义
void takeADate(Date d);



所以,将提供类定义(通过#include指令)的任务从你的函数声明头文件转交给包含函数调用的用户文件,就可以消除用户对类型定义的依赖,而这种依赖本来是不必要的、是人为造成的。
6.    不要在头文件中再包含其他头文件,除非缺少了它们就不能编译。相反,要一个一个地声明所需要的类,让使用这个头文件的用户自己去包含其他的头文件,以使用户代码最终得以通过编译。
7.    Person类仅仅用一个指针来指向某个不确定的实现,这样的类常常被称为句柄类(Handle Class)。对于指向的类来说,叫做主体类)。句柄类只是把所有函数的调用都转移到了对应的主体类中,主体类真正完成工作。如PersonImpl和Person含有一样的成员函数,他们的接口完全相同。使Person成为一个句柄类并不改变Person类的行为,改变的只是行为执行的地点。
8.    除了句柄类,另一个选择是使Person成为一种特殊类型的抽象基类,成为协议类。协议类没有实现;它存在的目的是为派生类确定一个接口。所以,他们一般没有数据成员,没有构造函数;有一个虚析构函数,还有一套纯虚函数,用于指定接口,如下所示:
class Person
{
public:
        virtual ~Person();
        virtual string name() const = 0;
        virtual string birthDate const = 0;
        virtual string address() const = 0;
        virtual string nationality() const = 0;
};


和句柄类的用户一样,协议类的用户只是在类的接口被修改的情况下才需要重新编译。

9.    句柄类和协议类分离了接口和实现,从而降低了文件间编译的依赖性。但这会带来代价:
    对于句柄类来说,成员函数必须通过(指向实现的)指针来获得对象数据。这样,每次访问的间接性就会多一层。此外,计算每个对象所占用的内存大小时,还应该算上这个指针。还有,指针本身还要被初始化(在句柄类的构造函数内),以使之指向被动态分配的实现对象,所以,还要承担动态内存分配(以及后续的内存释放)所带类的开销。
    对于协议类,每个函数都是虚函数,所以每次调用函数时必须承担间接跳转的开销。而且,每个从协议类派生而来的对象必然包含一个虚指针。这个指针可能会增加对象存储所需要的内存数量。
10.    句柄类和协议类都不大会使用内联函数。使用任何内联函数时都要访问实现细节,而设计句柄类和协议类的初衷正是为了避免这种情况。


《Effective C++》:条款31:将文件间的编译依存关系降至最低

将文件的编译依存关系降至最低,就是把各个文件之间的关联度降低。在修改一个文件后,编译时不需要重新编译很多文件。降低依存关系有几种手法,在文章中有讲。...
  • KangRoger
  • KangRoger
  • 2015年02月23日 23:07
  • 1712

c++将文件间的编译依赖性降至最低

  • sdl111
  • sdl111
  • 2006年05月24日 08:59
  • 872

条款34: 将文件间的编译依赖性降至最低

假设某一天你打开自己的C++程序代码,然后对某个类的实现做了小小的改动。提醒你,改动的不是接口,而是类的实现,也就是说,只是细节部分。然后你准备重新生成程序,心想,编译和链接应该只会花几秒种。毕竟,只...
  • zhongguoren666
  • zhongguoren666
  • 2012年11月07日 11:07
  • 757

条款34: 将文件间的编译依赖性降至最低 (转自effective c++ second edition)

假设某一天你打开自己的C++程序代码,然后对某个类的实现做了小小的改动。提醒你,改动的不是接口,而是类的实现,也就是说,只是细节部分。然后你准备重新生成程序,心想,编译和链接应该只会花几秒种。毕竟,只...
  • jaff20071234
  • jaff20071234
  • 2011年04月01日 10:27
  • 438

Effective C++条款34: 将文件间的编译依赖性降至最低

降低文件间编译依赖性 一般来说,发生重新链接的原因在于:将接口与实现分离,C++做的不好。C++类定义中不仅包括接口规范,还有不少实现。 定义时,编译器必须为它分配一个内存。编译器要知道内...
  • xwp3211
  • xwp3211
  • 2013年07月13日 21:52
  • 686

《Effective C++》:条款34:区分接口继承和实现继承

public继承的概念,由2部分构成:函数接口(function Interface)继承和函数实现(function implementation)继承。这两种继承的差异有点像函数的声明和函数的定义...
  • KangRoger
  • KangRoger
  • 2015年02月26日 23:36
  • 1333

将C++文件间的编译依赖性降至最低【ZZ】

源地址:http://user.qzone.qq.com/39177203/blog/1263969682 假设某一天你打开自己的C++程序代码,然后对某个类的实现做了小小的改动。提醒你,改...
  • juiceda
  • juiceda
  • 2012年07月28日 16:58
  • 488

条款31:将文件间的编译依存关系降至最低

条款31:将文件间的编译依存关系降至最低    (Minimize compilation dependencies between files.)内容:    在你们的开发团队中,一些有经验的工程师...
  • scofieldzhu
  • scofieldzhu
  • 2009年07月06日 11:39
  • 991

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

Effective C++笔记_条款31将文件间的编译依存关系降至最低       这个章节,读了两遍还是不是很清楚,有一种没法和作者沟通的感觉,看来我还是一个C++的初学者呀。好吧,不多说...
  • zdy0_2004
  • zdy0_2004
  • 2015年03月23日 23:46
  • 465

《Effective C++》:条款28-条款29

条款28避免返回handles指向对象内部成分:指的是不能返回对象内部数据/函数的引用、指针等。 条款29为异常安全而努力是值得的:指的是要有异常处理机制,避免发生异常时造成资源泄露等问题。...
  • KangRoger
  • KangRoger
  • 2015年02月19日 19:47
  • 1394
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:effective C++笔记之条款34: 将文件间的编译依赖性降至最低
举报原因:
原因补充:

(最多只允许输入30个字)