C++接口实现

面向对象的语言诸如JAVA提供了Interface来实现接口,但C++却没有这样一个东西,尽管C++ 通过纯虚基类实现接口,譬如COM的C++实现就是通过纯虚基类实现的(当然MFC的COM实现用了嵌套类),但我们更愿意看到一个诸如 Interface的东西。下面就介绍一种解决办法。

程序6步

 

    1、首先我们需要一些宏:

 

Cpp代码   收藏代码
  1. //********************************************  
  2. // Interface.h  
  3. //主要是宏定义一些关键词,可以形成接口类  
  4. //********************************************  
  5. #ifndef INTERFACE_H  
  6. #define INTERFACE_H  
  7.   
  8. #define Interface class  
  9.   
  10. #define DeclareInterface(name) Interface name { \  
  11. public: \  
  12.     virtual ~name() {}  
  13.   
  14. #define DeclareBasedInterface(name, base) class name : \  
  15. public base { \  
  16. public: \  
  17.         virtual ~name() {}  
  18.   
  19. #define EndInterface };  
  20.   
  21. #define implements public  
  22. #endif  
 

    2、有了这些宏,我们就可以这样定义我们的接口类:

 

Cpp代码   收藏代码
  1. //***********************************************  
  2. // IBar.h  
  3. //通过宏定义生成我们的接口类,写一些纯虚函数  
  4. //***********************************************  
  5. #ifndef IBAR_H  
  6. #define IBAR_H  
  7. #include "Interface.h"  
  8.   
  9. DeclareInterface(IBar)  
  10.   
  11. virtual int GetBarData() const = 0;  
  12. virtual void SetBarData(int nData) = 0;  
  13. EndInterface  
  14.   
  15. #endif  

     3、再写一个父类BasicBar.h

 

Cpp代码   收藏代码
  1. //***********************************************  
  2. // BasicBar.h  
  3. //Bar类的父亲类,用来继承测试  
  4. //***********************************************  
  5. #ifndef BASICBAR_H  
  6. #define BASICBAR_H  
  7. #include <iostream>  
  8. class BasicBar   
  9. {  
  10. public:  
  11.     BasicBar(int x)  
  12.     {  
  13.     }  
  14.   
  15.     ~BasicBar(){}  
  16.     virtual int getBarData1() const  
  17.     {  
  18.         std::cout <<"Get BasicBar!";  
  19.         return 0;  
  20.     }  
  21.   
  22.     virtual void setBarData1(int nData)  
  23.     {  
  24.     }  
  25. };  
  26. #endif  
 

  4、现在我们可以像下面这样来实现我们的接口Bar.h了:

 

Cpp代码   收藏代码
  1. //***********************************************  
  2. //Bar.h  
  3. //实现IBar接口的类  
  4. //***********************************************  
  5. #ifndef Bar_H  
  6. #define Bar_H  
  7. #include "Interface.h"  
  8. #include "BasicBar.h"  
  9. #include "IBar.h"  
  10.   
  11. #include <iostream>  
  12. class Bar :public BasicBar,implements IBar  
  13. {  
  14. public:  
  15.     Bar(int x=0) : BasicBar(x)  
  16.     {  
  17.     }  
  18.     ~Bar(){}  
  19.     virtual int getBarData() const  
  20.     {  
  21.         std::cout <<"Get Bar!";  
  22.         return 0;  
  23.     }  
  24.     virtual void setBarData(int nData)  
  25.     {  
  26.     }  
  27. };  
  28.   
  29. #endif  
 

    5、  怎么样,很简单吧,并不需要做很多的努力我们就可以在C++中使用接口了。在Main函数中引用我们的接口(我建立的是Qt 终端应用程序 )

 

Cpp代码   收藏代码
  1. //***********************************************  
  2. // main.h  
  3. //主函数  
  4. //***********************************************  
  5. #include <QtCore/QCoreApplication>  
  6. #include "IBar.h"  
  7. #include "DataAccess.h"  
  8. int main(int argc, char *argv[])  
  9. {  
  10.     QCoreApplication a(argc, argv);  
  11.     //IBar *bar = new Bar();  
  12.     IBar *bar = DataAccess::createBar();  
  13.     bar->getBarData();  
  14.     delete bar;  
  15.     return a.exec();  
  16. }  

 

另外的问题:C++中不许我们实例化抽象类,如IBar *bar = new IBar()


  我们只能通过上述main.cpp中的IBar *bar = new Bar();实现, 这样我们还必须指定实例化那个对象Bar,好像前面的努力都白费了啊!!那怎么办呢,我们需要一个工厂: 

6、建立一个数据工厂,DataAccess.h

 

Cpp代码   收藏代码
  1. //***********************************************  
  2. // DataAccess.h  
  3. //数据工厂,通过它调用对象类,返回给接口函数  
  4. //***********************************************  
  5. #ifndef DATAACCESS_H  
  6. #define DATAACCESS_H  
  7. #include "IBar.h"  
  8. #include "Bar.h"  
  9. class DataAccess   
  10. {  
  11.     // Construction & Destruction  
  12. public:  
  13.     DataAccess()  
  14.     {  
  15.     }  
  16.     ~DataAccess()  
  17.     {  
  18.     }  
  19.     static IBar* createBar()   
  20.     {  
  21.         //返回对象给IBar接口  
  22.         return(new Bar());   
  23.     }   
  24.       
  25. };  
  26. #endif  
   

  这个时候,我们把第5步的main.cpp调用接口方法改一下:

 

Cpp代码   收藏代码
  1. //***********************************************  
  2. // main.h  
  3. //主函数  
  4. //***********************************************  
  5. #include <QtCore/QCoreApplication>  
  6. #include "IBar.h"  
  7. #include "DataAccess.h"  
  8. int main(int argc, char *argv[])  
  9. {  
  10.     QCoreApplication a(argc, argv);  
  11.     //IBar *bar = new Bar();  
  12.     IBar *bar = DataAccess::createBar();  
  13.     bar->getBarData();  
  14.     delete bar;  
  15.     return a.exec();  
  16. }   
 

 

 

  整个过程中接口不负责任何具体操作,其他的程序要连接业务类、数据库的话,只需要构造一个业务对象、数据访问对象就OK,而不管工厂类如何变化。这就是接口的意义----抽象。

 

 

接口宏定义可以更简单点

    上述步骤中我们可以把步骤1和步骤2写的更简单些,我们只需要Interface 和 implements 的宏定义,

这样我们的接口定义类IBar灵活性更强,可以继续继承其他的接口类,也更符合java、C#等语言写接口类的风格。

步骤1:Interface.h

 

Cpp代码   收藏代码
  1. //********************************************  
  2. // Interface.h  
  3. //主要是宏定义一些关键词,可以形成接口类  
  4. //********************************************  
  5. #ifndef INTERFACE_H  
  6. #define INTERFACE_H  
  7.   
  8. #define Interface class  
  9.   
  10. //#define DeclareInterface(name) Interface name { \  
  11. //public: \  
  12. //  virtual ~name() {}  
  13. //  
  14. //#define DeclareBasedInterface(name, base) class name : \  
  15. //public base { \  
  16. //public: \  
  17. //      virtual ~name() {}  
  18. //  
  19. //#define EndInterface };  
  20.   
  21. #define implements public  
  22. #endif  

 步骤2:IBar.h

 

Cpp代码   收藏代码
  1. //***********************************************  
  2. // IBar.h  
  3. //通过宏定义生成我们的接口类,写一些纯虚函数  
  4. //***********************************************  
  5. #ifndef IBAR_H  
  6. #define IBAR_H  
  7. #include "Interface.h"  
  8. Interface IBar  
  9. {  
  10. public:  
  11.     virtual ~IBar(){}  
  12.     virtual int getBarData() const = 0;  
  13.     virtual void setBarData(int nData) = 0;  
  14. };  
  15.   
  16. //DeclareInterface(IBar)  
  17. //  
  18. //virtual int getBarData() const = 0;  
  19. //virtual void setBarData(int nData) = 0;  
  20. //EndInterface  
  21.   
  22. #endif  

备注:

  

然而,由于这种C++实现接口方式并不是语言本身所直接支持的特性,所以我们需要遵循一些规则:

         a)   声明一个类的时候,如果你的类除了要从接口类继承外还要从另一个类继承(结构上的继承,即is a关系),则把这个类作为第一个基类,就像我们平时做的一样,譬如CFrameWnd从CWnd继承,CBitmapButton从CButton继承,CMyDialog从CDialong继承。当你要从MFC类派生的时候,这尤其重要,把他们声明为第一个基类以避免破坏MFC的RuntimeClass机制。
         b)   其他的基类紧跟其后,有多少就跟多少,如果你需要的话。譬如:class Bar: public BasicBar, implements IBar, implements IOther, implements IWhatever, ...
         c)   接口类里面不要声明任何成员变量。接口类仅用于描述行为而不是数据。当你要作多重继承时,这样做可以避免数据成员被从同一个接口类多次继承。
         d)   接口类的所有成员函数定义为纯虚函数。这可以确保你的实现类来实现这些函数的全部,当然你也可以在抽象类实现部分函数,只要在你的派生类里实现剩下的函数。
         e)   不要从除了接口类的其他任何类派生你的接口类。DeclareBasedInterface()可以做到这个.普通类可以选择实现基接口还是派生的接口,后面一种意味着两者都要实现。
   f)  将一个指向实现接口的类的指针赋值给一个指向该接口类的指针是不需要强制类型转换的,但反过来将一个接口类的指针赋值给一个实现该接口的类的指针就需要 一个显式的强制类型转换。事实上我们可能会使用多重继承,这样这些转换我们就不能使用老式的转换。不过使用运行时类型信息(使用/GR选项)和动态类型转 换可以很好的工作当然也更安全。
   g) 此外dynamic_cast为你提供了一种查询一个对象或接口是否实现了一个指定的接口的途径。
   h) 你还要非常小心的避免不同接口函数的命名冲突。

         如果你仔细观察DeclareInterface 和 DeclareBasedInterfaca宏你会发现有一个操作是必须的:每个接口类都有一个虚析构函数。你可能认为这不重要,但是如果没有这个就可能会导致一些问题,看看下面的例子:就像你看到的一样,这里有一个类工厂,它根据BarType来创建一个IBar的实现,当你使用完以后你当然希望要delete该对象,你会像下面这样做:

 

Cpp代码   收藏代码
  1. int main()  
  2. {  
  3.    IBar* pBar = BarFactory::CreateBar(Bar);  
  4.    pBar->SetName("MyFooBar");  
  5.    delete pBar;    // Oops!  
  6. }  
 

        delete pBar 做了什么取决于该对象是否有一个虚析构函数。如果Bar没有一个虚析构函数,则只有IBar 的隐式的空析构函数被调用,Bar的析构函数不会被调用,这样就发生了内存泄露。接口类里虚析构函数的声明避免了这用状况,它确保每个实现接口的类都有一 个虚析构函数。

        当你使用DeclareInterfac的时候,记得使用EndInterface和它匹配。Interface 宏和 implements宏仅仅是代替了class和public,这看起来是多余的,但我认为它们更明确的表达了代码的意图。如果我这么写:class Bar: public IBar,你可能认为这只是一个简单的继承;但如果我这么写:class Bar: implements IBar,你就会看到它实际的价值和意图---这是对一个接口的实现,而不是简单的一次继承。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值