转
作者: Crazii @ CSDN
呵呵,本人是初学者,这边文章比较浅显,也只适合初学者.^_^
多态是OO的一大特点.通常我们把只有纯虚函数的抽象类,叫做接口类(Interface Class),或者是协议(Protocol).
习惯上类名会用大写I开头,但这不是必须的.比如下面的一个类声明.
- class IPool
- {
- public:
- virtual ~Pool() = 0 {}
- virtual void* allocate(size_t size) = 0;
- virtual void deallocate(void* p) = 0;
- virtual void destroy(void) = 0;
- };
下面简单说说使用抽象类的好处.
1.隐藏实现细节
因为真正的实现是由抽象类的继承类来实现的,所以这个接口的使用者并不需要关心它内部,具体是如何实现的.只需要了解它的功能特性,是用来干什么的.比如,现在IPool有两个继承版本,LargePool和SmallPool,使用者在使用的时候,可能是这样:
- //我现在想使用大容量的池.
- IPool* pool = PoolFactory->Create( PT_SMALL );
- ...
- //我现在又想使用小一点的池.
- IPool* pool = PoolFactory->Create( PT_LARGE );
- //甚至,没有多余的枚举和宏,而是是这样:
- //我现在想使用大容量的池.
- IPool* pool = PoolFactory->Create( _T("Large") );
- ...
- //我现在又想使用小一点的池.
- IPool* pool = PoolFactory->Create( _T("Small") );
这样,使用者只需要了解large和small对应的两个池的功能特点,并不关心他们是如何实现的.甚至根本不知道LargePool和SmallPool这两个类的代码声明.LargePool和SmallPool内部可能还有很多可用的成员数据和方法,但是只暴露出一部分子集供别人调用.
2.减少耦合性
不同的模块可能有不同的接口,一个稍复杂的内部实现,可能是两个接口的功能合并.这个时候,对一个接口做了大的调整,不会影响到另一个接口.呵呵,这样说有点绕,举个例子吧,一个模块ModuleA,提供了一个接口IB供模块ModuleB使用,也提供了一个接口IC供模块ModuleC使用.
在ModuleA的内部,IB和IC可能需要用同一个类ImplBC来实现,这个类只是把不同的子集提供给不同的模块使用.
这个时候如果对IB做了一些调整,那么,IC原来的接口不变.C模块不需要对调用代码做调整.
注意:另一种情况是,ImplBC这个类没有提供接口,而是把赤裸裸的类声明暴露给ModuleB和ModuleC,
这个时候,如果要调整对ModuleB的调用关系,只能是修改ImplBC的类声明.虽然对于ModuleC可能不需要修改源代码,但是ModuleC还是需要根据ImplBC头文件的变更,来重新编译一个新版本.仔细体会一下两者之间的区别.
你可能觉得重编译一下没有什么啊..如果你做过DLL给别人使用你就知道了,假如你发布了一个SDK供被人使用,你不能因为SDK中的DLL内部做的调整,也要求使用DLL的人也得根据你更新的头文件来重新编译一次吧.这种情况下,尽量不要调整接口,使用COM是最佳选择.试想一下,如果DX SDK每次更新,都要求你重新编译你的源代码,那是什么情况...
3.更实际的好处 编译时间快了
由于以上两个原因,这一点就很好理解了.相信一定有人遇到这样的情况: 有时可能只是对一个类的private成员数据做了一些调整,但是,结果是有大批大批的文件需要重新编译... 所以,根据情况,看看是不是需要,能不能使用接口类.