C++ 接口和对象分离的技术

来源:互联网 发布:mac 10.12.6 无法验证 编辑:程序博客网 时间:2024/04/27 04:25

 C++ 接口和对象分离的技术

这是Effective C++ Item 31的内容.

先看一下这个类

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;        // implementation detail
      Date theBirthDate;          // implementation detail
      Address theAddress;         // implementation detail
};

为了通过编译在这里在定义 Person 类的文件中,必须包含:

#include <string>
#include "date.h"
#include "address.h"

不幸的是,这样就建立了Person头文件和这些头文件之间的编译依赖关系。
显然,所有Person类的客户都依赖上面三个头文件.这可不是啥么好玩的事情.
一旦这些头文件所依赖的文件发生了变化,所有使用Person 类头文件的文件一样必须重新编译!!!!!

好在Effective C++给出两种解决的方法,个人倾向于第二种(这也是Jacobson的Minimal/Enxtension 理论推荐的),
虽然会牺牲一些运行时间和内存,但代码结构会很清晰也有利于扩展,这是后话.


1.Handle 方法

Person.h
#include <string>                     
#include <memory>                     
class PersonImpl;                     
class Date;                           
class Address;                        
class Person {
public:
 Person(const std::string& name, const Date& birthday,
        const Address& addr);
 std::string name() const;
 Date birthDate() const;
 Address address() const;
 ...

private:                                  
  std::tr1::shared_ptr<PersonImpl> pImpl; 
};                                        

Person.cpp
#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();
}

Date Person::birthDate() const
{
  return pImpl->birthDate();
}

Address Person::address() const
{
  return pImpl->address();
}


PersonImpl.h
#include <string>
#include "date.h"
#include "address.h"

class PersonImpl {
public:
  PersonImpl(const std::string& name, const Date& birthday,
         const Address& addr);
  std::string name() const;
  Date birthDate() const;
  Address address() const;
  ...

private:
      std::string theName;        // implementation detail
      Date theBirthDate;          // implementation detail
      Address theAddress;         // implementation detail
};

PersonImpl.cpp

#include "PersonImpl.h"
PersonImpl::PersonImpl(const std::string& name, const Date& birthday,
               const Address& addr)
:theName(name),
theBirthDate(birthday),
theAddress(addr)
{
}

std::string PersonImpl::name() const
{
  return theName;
}
Date PersonImpl::birthDate() const
{
  return theBirthDate;
}
Address PersonImpl::address() const
{
  return theAddress;
}

 

2.Abstrat Interface 方法

一个 Person 的 Interface 类可能就像这样

class Person {
public:
  virtual ~Person();

  virtual std::string name() const = 0;
  virtual Date birthDate() const = 0;
  virtual Address address() const = 0;
};

这个类的客户必须针对 Person 的指针或引用编程,因为实例化包含纯虚函数的类是不可能的。

一个 Interface 类的客户必须有办法创建新的对象。
他们一般通过调用一个为“可以真正实例化的派生类”扮演构造函数的角色的函数做到这一点的。
class Person {
public:
 ...

 static std::tr1::shared_ptr<Person>    // return a tr1::shared_ptr to a new
   create(const std::string& name,      // Person initialized with the
          const Date& birthday,         // given params; see Item 18 for
          const Address& addr);         // why a tr1::shared_ptr is returned
 ...
};


RealPerson.h

class RealPerson: public Person {
public:
  RealPerson(const std::string& name, const Date& birthday,
             const Address& addr)
  : theName(name), theBirthDate(birthday), theAddress(addr)
  {}

  virtual ~RealPerson() {}

  std::string name() const;        // implementations of these
  Date birthDate() const;   // functions are not shown, but
  Address address() const;     // they are easy to imagine

private:
  std::string theName;
  Date theBirthDate;
  Address theAddress;
};

原创粉丝点击