编译依存关系最小化

最近在做一个不算大的项目,编写的头文件也就6-7个左右,再加上用上了OpenCV库与Eigen库,所以编译的时候特别蛋疼,一堆的warning,而且都是一样的warning,因为一个头文件里有warning出现,然后又有其他几个头文件包含了这个出现“warning”的头文件,所以这编译的输出又刷屏了!这样我想起当初玩WOW的时候用自动宏刷屏。- -

关键的是,这拖慢了编译速度。还好<<Effective C++>>这本书看到了条款31,有降低编译依存关系的方法。书里介绍了两种方法:Handle class,Interface class.下面我重点介绍一下Handle class的方法。

这个方法设计到class的定义与声明。有的情况下,必须给出class的定义,才能使用该class及其相关的东西,如:

Date birthday;
这种情况下就必须给出Date类的定义,如包含定义其的头文件:
#include "Date.h"
否则无法通过编译。

有的情况下,给出class的声明即可。如该class的对象当形参,或者定义一个该class的指针或引用:

class Date;  //声明
Date today();  //没问题
void getWeather(Date d);   //当形参
Date *someOneBirthday;   //定义指针
以上都能通过编译,而仅仅作class的声明就可以。

所以,尽量跟着这条光明大道走:

1. 如果能使用对象引用(object references)或者对象的指针(object pointers)可以完成任务,就不用使用对象(objects)。

2. 如果能够,尽量以class声明式代替class的定义式。

还有一个技巧就是: 

为声明式和定义式提供不同的头文件。

如:

#include "datefwd.h"
即刚才class Date的声明头文件。

下面举一个血淋淋的例子。

#include <memory>
#include <string>
#include "Address.h"
#include "Date.h"
using namespace std;
class Person
{
	//tr1::shared_ptr<PersonImpl> pImpl;
	string	mName;
	Date	mBirthDate;
	Address	mAddress;
public:
	Person(const string& name, const Date& birthday, 
		const Address& address);
	/* 偷偷懒,只写一个get函数 */
	string getmName() const;
};
看我的Person class里,由于跟Date与Address关联,所以必须包含着两个class的头文件,如果跟更多的类关联的话,你就要包含更多的头文件,然后,你就可以享受被刷屏的乐趣了。

Handle class的方法则是把Person类分割成2个classes,一个提供接口一个提供实现。下面可以看到,如何把那些烦人的与外部类关联的成员封装到另外一个实现类(PersonImpl),然后在Person类风骚地定义一个指向PersonImpl的指针。好吧,有了这个指针,我就对那些外部关联的class作一个声明就行了。

Person的定义:

#include "DependFwd.h"	//我是声明头文件
#include <memory>
#include <string>
using namespace std;
class Person
{
	tr1::shared_ptr<PersonImpl> pImpl;  //这个是智能指针
public:
	Person(const string& name, const Date& birthday, 
		const Address& address);
	/* 偷偷懒,只写一个get函数 */
	string getmName() const;
};
来看看PersonImpl类怎么定义:

/* 包含其定义式才能使用 */
#include "Date.h"
#include "Address.h"
using namespace std;
/* Person接口实现类 */
class PersonImpl
{
	/* 原来Person的成员都在这定义了 */
	string	mName;		
	Date	mBirthDate;
	Address	mAddress;
public:
	/* 构造函数 */
	PersonImpl(const string& name, const Date& birthday, 
		const Address& address)
		:mName(name), mBirthDate(birthday), mAddress(address)
	{}
	/* 获取姓名 */
	string getmNmae() const{ return mName;}
	/* 生日和地址的获取函数就不写了 */
};


Date与Address我就省略了,来看看声明头文件DependFwd.h:

class Address;
class Date;
class PersonImpl;
只有三行。

测试一下:

#include <iostream>
#include "Person.h"
#include "Date.h"
#include "Address.h"
using namespace std;
int main()
{
    Date	birthday;
    Address 	address;
    Person	p("John", birthday, address);
    cout << p.getmName() << endl;
    system("pause");
    return 0;
}

输出

John

当然,使用这些最小化编译依存关系的方法,对程序运行效率还是有所影响的,而且消耗的内存量也有所增加。不过这也解除了接口和实现之间的耦合关系。

如果大家还记得80-20原则:

80%的运行时间都消耗在其中20%的代码上。

所以,还是不要放弃上面提到的技术,如果愿意的话,还是对那80%对效率影响不大的代码作一些结构上的优化,而把提高效率的重心放在另外那20%的代码上。


以后有空的话会写一些Interface classes的方法。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值