`
qimo601
  • 浏览: 3449342 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
最新评论

C++接口实现总结

阅读更多

网上的例子,稍微有点错误。我给更改一下,附件上有源码!如有错误,请指正。

总结一下C++实现接口的技巧。


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

程序6步

 

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

 

//********************************************
// Interface.h
//主要是宏定义一些关键词,可以形成接口类
//********************************************
#ifndef INTERFACE_H
#define INTERFACE_H

#define Interface class

#define DeclareInterface(name) Interface name { \
public: \
	virtual ~name() {}

#define DeclareBasedInterface(name, base) class name : \
public base { \
public: \
		virtual ~name() {}

#define EndInterface };

#define implements public
#endif
 

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

 

//***********************************************
// IBar.h
//通过宏定义生成我们的接口类,写一些纯虚函数
//***********************************************
#ifndef IBAR_H
#define IBAR_H
#include "Interface.h"

DeclareInterface(IBar)

virtual int GetBarData() const = 0;
virtual void SetBarData(int nData) = 0;
EndInterface

#endif

     3、再写一个父类BasicBar.h

 

//***********************************************
// BasicBar.h
//Bar类的父亲类,用来继承测试
//***********************************************
#ifndef BASICBAR_H
#define BASICBAR_H
#include <iostream>
class BasicBar 
{
public:
	BasicBar(int x)
	{
	}

	~BasicBar(){}
	virtual int getBarData1() const
	{
		std::cout <<"Get BasicBar!";
		return 0;
	}

	virtual void setBarData1(int nData)
	{
	}
};
#endif
 

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

 

//***********************************************
//Bar.h
//实现IBar接口的类
//***********************************************
#ifndef Bar_H
#define Bar_H
#include "Interface.h"
#include "BasicBar.h"
#include "IBar.h"

#include <iostream>
class Bar :public BasicBar,implements IBar
{
public:
	Bar(int x=0) : BasicBar(x)
	{
	}
	~Bar(){}
	virtual int getBarData() const
	{
		std::cout <<"Get Bar!";
		return 0;
	}
	virtual void setBarData(int nData)
	{
	}
};

#endif
 

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

 

//***********************************************
// main.h
//主函数
//***********************************************
#include <QtCore/QCoreApplication>
#include "IBar.h"
#include "DataAccess.h"
int main(int argc, char *argv[])
{
	QCoreApplication a(argc, argv);
	//IBar *bar = new Bar();
	IBar *bar = DataAccess::createBar();
	bar->getBarData();
	delete bar;
	return a.exec();
}

 

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


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

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

 

//***********************************************
// DataAccess.h
//数据工厂,通过它调用对象类,返回给接口函数
//***********************************************
#ifndef DATAACCESS_H
#define DATAACCESS_H
#include "IBar.h"
#include "Bar.h"
class DataAccess 
{
	// Construction & Destruction
public:
	DataAccess()
	{
	}
	~DataAccess()
	{
	}
	static IBar* createBar() 
	{
		//返回对象给IBar接口
		return(new Bar()); 
	} 
	
};
#endif
   

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

 

//***********************************************
// main.h
//主函数
//***********************************************
#include <QtCore/QCoreApplication>
#include "IBar.h"
#include "DataAccess.h"
int main(int argc, char *argv[])
{
	QCoreApplication a(argc, argv);
	//IBar *bar = new Bar();
	IBar *bar = DataAccess::createBar();
	bar->getBarData();
	delete bar;
	return a.exec();
} 
 

 

 

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

 

 

接口宏定义可以更简单点

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

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

步骤1:Interface.h

 

//********************************************
// Interface.h
//主要是宏定义一些关键词,可以形成接口类
//********************************************
#ifndef INTERFACE_H
#define INTERFACE_H

#define Interface class

//#define DeclareInterface(name) Interface name { \
//public: \
//	virtual ~name() {}
//
//#define DeclareBasedInterface(name, base) class name : \
//public base { \
//public: \
//		virtual ~name() {}
//
//#define EndInterface };

#define implements public
#endif

 步骤2:IBar.h

 

//***********************************************
// IBar.h
//通过宏定义生成我们的接口类,写一些纯虚函数
//***********************************************
#ifndef IBAR_H
#define IBAR_H
#include "Interface.h"
Interface IBar
{
public:
	virtual ~IBar(){}
	virtual int getBarData() const = 0;
	virtual void setBarData(int nData) = 0;
};

//DeclareInterface(IBar)
//
//virtual int getBarData() const = 0;
//virtual void setBarData(int nData) = 0;
//EndInterface

#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该对象,你会像下面这样做:

 

int main()
{
   IBar* pBar = BarFactory::CreateBar(Bar);
   pBar->SetName("MyFooBar");
   delete pBar;    // Oops!
}
 

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

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

 

分享到:
评论
4 楼 qimo601 2013-04-12  
说实话,具体我也说不出清楚。我只知道以前用java编程,接口对项目管理很有好处。
你看看CSDN上的java与C++接口的区别。
http://bbs.csdn.net/topics/477099

meiwm 写道
= =、 我明白这是要实现接口机制,但不太理解楼上说的向java编程风格靠拢指的是什么(接口这种机制和风格是一个概念么)?这样实现接口还有个坑爹的问题就是 一旦接口函数签名有自定义类型的返回值时(很遗憾,这经常会碰到)。

#define Interface class 
Interface IBase {}
class Derive : public IBase {}

void main(...)
{
  IBase *ba = new Derive;
}



是不是这样定义有什么弊端呢?



兄弟,文章开头已经说明了。这是想向java编程风格靠拢。java里有“接口”这种定义,C++没有。

class Bar :public BasicBar,implements IBar 
meiwm 写道
= =、 我明白这是要实现接口机制,但不太理解楼上说的向java编程风格靠拢指的是什么(接口这种机制和风格是一个概念么)?这样实现接口还有个坑爹的问题就是 一旦接口函数签名有自定义类型的返回值时(很遗憾,这经常会碰到)。

#define Interface class 
Interface IBase {}
class Derive : public IBase {}

void main(...)
{
  IBase *ba = new Derive;
}



是不是这样定义有什么弊端呢?



兄弟,文章开头已经说明了。这是想向java编程风格靠拢。java里有“接口”这种定义,C++没有。

class Bar :public BasicBar,implements IBar 
3 楼 meiwm 2013-04-07  
= =、 我明白这是要实现接口机制,但不太理解楼上说的向java编程风格靠拢指的是什么(接口这种机制和风格是一个概念么)?这样实现接口还有个坑爹的问题就是 一旦接口函数签名有自定义类型的返回值时(很遗憾,这经常会碰到)。

#define Interface class 
Interface IBase {}
class Derive : public IBase {}

void main(...)
{
  IBase *ba = new Derive;
}



是不是这样定义有什么弊端呢?



兄弟,文章开头已经说明了。这是想向java编程风格靠拢。java里有“接口”这种定义,C++没有。

class Bar :public BasicBar,implements IBar 
2 楼 qimo601 2013-03-29  
meiwm 写道
为什么不直接用 命名规范约束~~,这样定义和使用时也更“自然”

#define Interface class 
Interface IBase {}
class Derive : public IBase {}

void main(...)
{
  IBase *ba = new Derive;
}



是不是这样定义有什么弊端呢?




兄弟,文章开头已经说明了。这是想向java编程风格靠拢。java里有“接口”这种定义,C++没有。

class Bar :public BasicBar,implements IBar 
1 楼 meiwm 2013-03-24  
为什么不直接用 命名规范约束~~,这样定义和使用时也更“自然”

#define Interface class 
Interface IBase {}
class Derive : public IBase {}

void main(...)
{
  IBase *ba = new Derive;
}



是不是这样定义有什么弊端呢?

相关推荐

    C++库封装JNI接口-实现java调用c++

    总结,C++库封装JNI接口实现Java调用C++涉及的主要步骤包括:声明Java中的本地方法,生成JNI头文件,编写C++实现,编译成库,最后在Java中加载并调用。这个过程需要理解Java和C++之间的数据类型转换,以及如何在两种...

    Creo二次开发 C++接口开发使用说明书

    ### Creo二次开发 C++接口开发使用说明书 #### 一、引言 在现代工业设计与制造领域,Creo作为一款先进的三维CAD软件,被广泛应用于产品设计与工程分析之中。随着技术的发展与用户需求的增长,对Creo进行二次开发的...

    C++实现 Https Server 支持 restful json

    总结一下,实现"C++实现Https Server支持restful json"涉及到以下步骤: 1. 引入如Poco这样的第三方库以支持HTTPS和HTTP处理。 2. 创建SSL上下文,加载服务器证书和私钥。 3. 设置服务器套接字并开始监听HTTPS连接...

    C++头文件转JAVA JNA接口类

    JNA通过定义Java接口来映射C/C++函数,并在运行时动态加载本地库,实现调用。这极大地简化了Java代码与C/C++代码之间的交互过程。 要将C++头文件转换为JNA接口,我们通常会使用一个名为SWIG(Simplified Wrapper ...

    C++接口定义及实现举例

    总结来说,C++中的接口主要通过抽象基类和纯虚函数实现,提供了模块间的解耦和多态性。通过接口,我们可以在不关心具体实现的情况下调用功能,这在大型项目或跨模块通信中尤为重要。在实际编程中,接口的设计和使用...

    C++实现的文件传输功能

    总结起来,C++实现文件传输功能涉及的关键知识点包括: 1. 使用`fstream`库进行文件的读写操作。 2. 套接字编程,包括创建、绑定、监听、接受连接以及发送和接收数据。 3. 可能的多线程编程,利用`&lt;thread&gt;`库实现...

    基于c++实现的GRPC服务端demo

    总结,基于 C++ 的 gRPC 服务端 demo 主要涉及以下步骤:定义服务和消息类型、生成服务接口和消息类、实现服务逻辑、启动 gRPC 服务器以及编写客户端进行测试。gRPC 结合 C++ 的强大功能,提供了高效、可靠的分布式...

    wind c++接口

    Wind C++接口是上海万得信息技术股份有限公司(Wind资讯)提供给编程用户的一套C++编程接口,允许用户通过C++语言编写程序来访问和操作Wind股票软件中的数据,从而实现各类数据的查询以及交易功能。这些接口被广泛...

    C++调用HTTP实现方式

    ### C++调用HTTP实现方式详解 #### 一、引言 在现代软件开发中,HTTP(HyperText Transfer Protocol)协议被广泛应用于客户端与服务器之间的通信。C++作为一种强大的编程语言,同样支持对HTTP协议的操作。本文将...

    基于C++实现简易AES加解密算法

    总结来说,实现基于C++的简易AES加解密算法涉及密码学理论、C++编程技巧和数据安全实践。在具体实现过程中,需要理解和掌握AES的内部工作原理,以及如何在C++中有效地表示和操作数据,以确保算法的正确性和效率。...

    线程池原理及创建(C++实现)

    ### 线程池原理及创建(C++实现) #### 一、线程池的重要性 在现代计算环境中,网络服务器面临着处理大量并发请求的挑战,其中包括但不限于Web服务器、电子邮件服务器和数据库服务器。这类服务器通常需要在短时间...

    3DES C++接口

    《3DES C++接口开发详解》 3DES(Triple Data Encryption ...总结来说,3DES C++接口的开发涉及密钥管理、子密钥生成、加密解密过程以及性能监控。通过理解这些关键点,开发者可以构建一个安全且高效的文件加密系统。

    总结下C++中模块(Dll)对外暴露接口的方式

    总结下C++中模块(Dll)对外暴露接口的方式: (1)导出API函数的方式 (2)导出类方式 (3)COM方式

    C++ 支付宝付款对接,支持回调url,实测可用!

    总结,通过`AlipayOpenapiCpp-master`项目,开发者可以学习到如何在C++环境中集成支付宝接口,实现支付功能,并利用回调URL来获取并处理支付结果。这不仅对C++开发者具有指导意义,对于理解支付系统的架构和流程也...

    桥接模式 C++ 实现

    桥接模式是一种设计...在C++中,我们可以利用类的继承和接口来实现这一模式,从而提高代码的可扩展性和可维护性。在实际项目中,尤其是在需要处理多个抽象层次和实现方式的情况下,桥接模式是一个非常有价值的工具。

    AES CBC ECB C++代码实现

    在提供的C++源码中,你将找到实现了AES加密的类或函数,可能包括`AES_ECB_Encrypt`、`AES_CBC_Encrypt`等接口。使用这些API时,你需要提供密钥、明文数据、以及在CBC模式下所需的初始化向量。例如: ```cpp #...

    C语言实现C++多态

    总结起来,虽然C语言不具备C++那样的内置多态机制,但通过函数指针和结构体,我们可以实现类似的功能。这种方法需要更高的编程技巧和更严谨的设计,但在某些场合下,如嵌入式系统或性能要求极高的场景,可能是一种...

Global site tag (gtag.js) - Google Analytics