//条款31 将文件间的编译依存关系降至最低
/*
Handle class
简而言之,将类的接口和实现分离。
接口里面存储一个指针,指向实现类,然后客户调用接口。
这样当实现改变时候,客户不用重编译。
Handle Class (Person.h PersonImpl.h PersonImpl.cpp)
Person的客户就与Person的实现细目分离,Person实现的修改不需要Person客户端重新编译。
接口与实现分离。一个只负责提供接口,另一个负责实现该接口。main class(Person)内含有一个指针成员
shared_ptr<PersonImpl>pImpl.(pimpl pointer to implementation)。Person客户完全与Person实现细目分离。
这个分离的关键在于以“声明的依存性”替换“定义的依存性”。现实中让头文件尽可能自我满足,万一做不到,
则让它与其它文件内的声明式(而非定义式)相依。
*/
/*
Interface class
简而言之,将类抽象为接口,然后客户调用接口,这样当类的实现改变时不会受影响。
类的实现通过继承抽象基类完成。
客户调用的构造接口是static,因为它定义在抽象基类中,而抽象基类不能实例化,
只能在实例化派生类时部分实例化,所以定义成static。static的函数属于整个类,
可以通过类名::函数名的方式调用,具体构造函数在派生类中定义。
另一种制作Handle class的办法是,令Person称为抽象基类,称为:
Interface Class (Person2.h Person2.cpp RealPerson2.h)
Person类定义成抽象基类,成为接口。这个class的客户必须以Person的指针或引用来撰写应用程序。
Interface class的客户通常调用factory(工厂)函数或virtual构造函数。它们返回指针(或智能指针),指向
动态分配所得对象,而该对象支持Interface class的接口。这样的函数又往往在Interface class内被
声明为static。
支持Interface class接口的那个具象类(concrete classes)必须被定义出来,而且真正的构造函数必须被调用。
它提供继承而来的virtual函数的实现。
*/
Handle class
Person.h
#include <string>
#include <memory>
using namespace std;
class PersonImpl; // Person实现类的前置声明
class Person
{
public:
Person(const string& name);
string getname() const;
private:
tr1::shared_ptr<PersonImpl> pImpl; // 指针,指向实现物,或者PersonImpl* pImpl
string name;
};
#include "stdafx.h"
#include "Person.h"
#include "PersonImpl.h"
Person::Person(const string& name) : pImpl(new PersonImpl(name))
{
this->name = name;
}
string Person::getname() const
{
return pImpl->getname();
}
PersonImpl.h
#include <string>
#include <iostream>
using namespace std;
class PersonImpl
{
public:
PersonImpl(const string& name)
{
this->name = name;
//cout << "Impl" << endl;
}
string getname() const;
private:
string name;
};
PersonImpl.cpp
#include "stdafx.h"
#include "PersonImpl.h"
string PersonImpl::getname() const
{
return this->name;
}
main.cpp
#include "stdafx.h"
#include "Person.h"
#include <memory>
#include <iostream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
// Handle Class
Person p("Yerasel");
cout << p.getname() << endl;
return 0;
}
以上方法是pImpl方法,它是微软的Herb Sutter提出来的,该方法是为了尽量减小接口和实现之间的耦合,以避免接口改动对程序重新编译等带来的影响。简单来说,如果你的大型程序因为复杂的头文件包含关系,使得你对某头文件的某小改动可能引起的巨大编译时间成本望而生畏,那么你需要用pImpl方法来改善这种处境。
Interface class
Person2.h
#ifndef PER2_H
#define PER2_H
#include <string>
#include <memory>
using namespace std;
class Person2
{
public:
Person2(const string& name)
{
this->thename = name;
}
virtual ~Person2(){};
static tr1::shared_ptr<Person2> create(const string& name);
virtual string getname() const = 0;
private:
string thename;
};
#endif
Person2.cpp
#include "stdafx.h"
#include "Person2.h"
#include "RealPerson2.h"
#include <memory>
tr1::shared_ptr<Person2> Person2::create(const string& name)
{
return tr1::shared_ptr<Person2>(new RealPerson2(name));
}
RealPerson2.h
#ifndef REAL2_H
#define REAL2_H
#include "Person2.h"
#include <iostream>
using namespace std;
class RealPerson2 : public Person2
{
public:
RealPerson2(const string& name)
:Person2(name), thename(name)
{
}
virtual ~RealPerson2(){}
string getname() const
{
return this->thename;
}
private:
string thename;
};
#endif
main.cpp
#include "stdafx.h"
#include "Person.h"
#include <memory>
#include <iostream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
// Interface Class
tr1::shared_ptr<Person2>p2 = (Person2::create("jandosim"));
cout << p2->getname() << endl;
return 0;
}
附注,shared_ptr示例
//工厂模式
class abstract
{
public:
virtual void f()=0;
virtual void g()=0;
protected:
virtual ~abstract(){}
};
class impl:public abstract
{
public:
virtual void f()
{
cout << "class impl f" << endl;
}
virtual void g()
{
cout << "class impl g" << endl;
}
};
tr1::shared_ptr<abstract> create()
{
return tr1::shared_ptr<abstract>(new impl);
}
int _tmain(int argc, _TCHAR* argv[])
{
tr1::shared_ptr<abstract> a = create();
a->f();
a->g();
return 0;
}
运行环境VS2008,参考书籍《Effective C++ 3rd》