C 中接口和实现分离的技术

2008-02-23 05:33:18来源:互联网 阅读 ()

新老客户大回馈,云服务器低至5折

在用C 写要导出类的库时,我们经常只想暴露接口,而隐藏类的实现细节。也就是说我们提供的头文档里只提供要暴露的公共成员函数的声明,类的其他任何信息都不会在这个头文档里面显示出来。这个时候就要用到接口和实现分离的技术。

  下面用一个最简单的例子来说明。

   类ClxExp是我们要导出的类,其中有一个私有成员变量是ClxTest类的对象,各个文档内容如下:

   lxTest.h文档内容:  

  class ClxTest

  {

  public:

   ClxTest();

   virtual ~ClxTest();  

   void DoSomething();

  };  

   lxTest.cpp文档内容:  

  #include "lxTest.h"  

  #include

  using namespace std;  

  ClxTest::ClxTest()

  {

  }  

  ClxTest::~ClxTest()

  {

  }  

  void ClxTest::DoSomething()

  {

   cout << "Do something in class ClxTest!" << endl;

  }
  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////  

  lxExp.h文档内容:  

 #include "lxTest.h"  

  class ClxExp  

 {

  public:

   ClxExp();

   virtual ~ClxExp();  

   void DoSomething();  

  private:

   ClxTest m_lxTest;  

   void lxTest();

  }; 

  lxExp.cpp文档内容:  

  #include "lxExp.h"  

  ClxExp::ClxExp()

  {

  }  

  ClxExp::~ClxExp()

  {

  }  

  // 其实该方法在这里并没有必要,我这样只是为了说明调用关系

  void ClxExp::lxTest()

  {

   m_lxTest.DoSomething();

  }  

  void ClxExp::DoSomething()

  {

   lxTest();

  }  

  为了让用户能使用我们的类ClxExp,我们必须提供lxExp.h文档,这样类ClxExp的私有成员也暴露给用户了。而且,仅仅提供lxExp.h文档是不够的,因为lxExp.h文档include了lxTest.h文档,在这种情况下,我们还要提供lxTest.h文档。那样ClxExp类的实现细节就全暴露给用户了。另外,当我们对类ClxTest做了修改(如添加或删除一些成员变量或方法)时,我们还要给用户更新lxTest.h文档,而这个文档是跟接口无关的。假如类ClxExp里面有很多像m_lxTest那样的对象的话,我们就要给用户提供N个像lxTest.h那样的头文档,而且其中任何一个类有改变,我们都要给用户更新头文档。更有一点就是用户在这种情况下必须进行重新编译!上面是很小的一个例子,重新编译的时间能够忽略不计。但是,假如类ClxExp被用户大量使用的话,那么在一个大项目中,重新编译的时候我们就有时间能够去喝杯咖啡什么的了。当然上面的种种情况不是我们想看到的!您也能够想像一下用户在自己程式不用改变的情况下要不停的更新头文档和编译时,他们心里会骂些什么。其实对用户来说,他们只关心类ClxExp的接口DoSomething()方法。那我们怎么才能只暴露类ClxExp的DoSomething()方法而不又产生上面所说的那些问题呢?答案就是--接口和实现的分离。我能够让类ClxExp定义接口,而把实现放在另外一个类里面。下面是具体的方法:  

  首先,添加一个实现类ClxImplement来实现ClxExp的任何功能。注意:类ClxImplement有着跟类ClxExp相同的公有成员函数,因为他们的接口要完全一致。

  lxImplement.h文档内容:

  #include "lxTest.h"  

  class ClxImplement

  {

  public:

   ClxImplement();

   virtual ~ClxImplement();  

   void DoSomething();  

  private:

   ClxTest m_lxTest;  

   void lxTest();

  }; 

   lxImplement.cpp文档内容:  

  #include "lxImplement.h"  

  ClxImplement::ClxImplement()

  {

  }  

  ClxImplement::~ClxImplement()

  {

  }  

  void ClxImplement::lxTest()

  {

   m_lxTest.DoSomething();

  }  

  void ClxImplement::DoSomething()

  {

   lxTest();

  }  

   然后,修改类ClxExp。  

   修改后的lxExp.h文档内容:  

  // 前置声明

  class ClxImplement; 

  class ClxExp

  {

  public:

   ClxExp();

   virtual ~ClxExp();  

   void DoSomething();  

  private:

   // 声明一个类ClxImplement的指针,无需知道类ClxImplement的定义

   ClxImplement *m_pImpl;

  };  

   修改后的lxExp.cpp文档内容:  

  // 在这里包含类ClxImplement的定义头文档

  #include "lxImplement.h"  

  ClxExp::ClxExp()

  {

   m_pImpl = new ClxImplement;

  }  

  ClxExp::~ClxExp()

  {

   delete m_pImpl;

  }  

  void ClxExp::DoSomething()

  {

   m_pImpl->DoSomething();

  }  

  通过上面的方法就实现了类ClxExp的接口和实现的分离。请注意两个文档中的注释。类ClxExp里面声明的只是接口而已,而真正的实现细节被隐藏到了类ClxImplement里面。为了能在类ClxExp中使用类ClxImplement而不include头文档lxImplement.h,就必须有前置声明class ClxImplement,而且只能使用指向类ClxImplement对象的指针,否则就不能通过编译。在发布库文档的时候,我们只需给用户提供一个头文档lxExp.h就行了,不会暴露类ClxExp的任何实现细节。而且我们对类ClxTest的任何改变,都无需再给用户更新头文档(当然,库文档是要更新的,但是这种情况下用户也不用重新编译!)。这样做更有一个好处就是,能够在分析阶段由系统分析员或高级程式员来先把类的接口定义好,甚至能够把接口代码写好(例如上面修改后的lxExp.h文档和lxExp.cpp文档),而把类的具体实现交给其他程式员研发。

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇: 奇怪的返回:ask :ask

下一篇: 用VC 实现http代理