C++ 将文件间的编译依存关系降到最低

20180320 C++ 将文件间的编译依存关系降到最低


当对C++程序的某个class实现文件做了些微修改,再重新建置这个文件,会花费很长时间,,因为C++没有把“将接口从实现中分离”这事做的很好。Class的定义式不只详细叙述了class接口,还包括十足的实现细节,eg:
class Person{
public:
  Person(const std::string& name,const Date& birthday,
         const Address& addr);
  std::string name() const;
  std::string birthDate() const;
  std::string address() const;
  ...
private:
  std::string theName;  //实现细节
  Date theBirthDate;  //实现细节
  Address theAddress;  //实现细节 
}


这里的class Person无法通过编译--若编译器没有取得其实现代码所用到的class string,Data和Address的定义式。这样的定义式通常由#include指示符提供,所以Person定义文件的最上方很可能存在这样的东西:
#include<string>
#incude"date.h"
#include"address.h"


这样就是在Person定义文件和其含入文件之间形成了一种编译依存关系(compilation dependency),若这些头文件中有任何一个被改变,或这些头文件所依赖的其他头文件有任何改变,那么每一个含入Person class的文件就得重新编译,任何使用Person class的文件也必须重新编译。


针对Person可以这样做:把Person分割为两个classes,一个提供接口,另一个负责实现接口。若负责实现的那个所谓implementation class取名为PersonImpl,Person将定义如下:


#include<string>//标准程序库组件不该被前置声明
#include<memory>//此乃为了tr1::shared_ptr而含入


class PersonImpl;//Person实现类的前置声明
class Date;//Person接口用到的classes的前置声明
class Address;


class Person{
public :
  Person(const std::string& name,const Ddate& birthday,
         const Address& addr);
  std::string name() const;
  std::string birthdate() const;  
  std::string address() const;
  ...
private:
  std::tr1::shared_ptr<PersonImpl> pImpl;//指针,指向实现物
}


在这里,main class(Person)只内含一个指针成员(这里使用tr1::shared_ptr),指向其实现类(PersonImpl)。这样的设计常被称为pimpl idiom(pimpl是"pointer to implementation"的缩写)。这种classes内的指针名称往往就是pImpl,就像上面代码那样。
这样的设计之下,person的客户就完全与Dates,Addresses以及Persons的实现细节分离了。


注意:
1、若使用object references或object pointers可以完成任务,就不要使用objects。
2、请尽量以class声明式替换class定义式。
3、为声明式和定义式提供不同的头文件。


像Person这样使用pimpl idiom的classes,往往被称为Handle classes。但这样的classes如何真正做事呢,办法之一是将它们的所有函数转交给相应的实现类(implementation classes)并由后者完成实际工作。如下面的Person两个成员函数实现:


#include"Person.h"//
#include"PersonImpl.h"


Person::Person(const std::string& name,const Date& birthday,
               const Address& addr)
               :pImpl(new PersonImpl(name,birthday,addr))
               {}
std::string Person::name() const 
{
  return pImpl->name();
}


注意:
1、支持"编译依存性最小化"的一般构想是:相依于声明式,不要相依于定义式。基于此构想的两个手段是Handle classes和Interface classes。
2、程序库头文件应该以“完全且仅有声明式”(full and declaration-only forms)的形式存在。这种做法不论是否涉及template都适用。






























评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值