interface接口实例
C++标准中是没有接口interface的,但是我们在MFC的程序中经常可以看到接口的影子,我就自己查阅的资料和理解,做一个总结把。
首先,在objBase.h里面,有interface的定义
#define __STRUCT__ struct
#define interface __STRUCT__
这样我们就能知道,interface只不过是struct的重命名
但是为什么要把struct定义为interface呢,这其中大有渊源,接着往下看:
在C++中struct与Class可以说是没有区别,但是又可以说是很大区别。
因为C++要向下兼容C。所以C具有的东西,那么在C++里也具有。所以谈struct应该是从C谈起 struct在C中:struct是一种自定义的数据类型。既然是一种数据类型那么就肯定不能定义函数。C是面向过程的,面向对象的东西它自然也不具有。 struct在C++中;C++是面向对象的。根据对象的思想,struct应该是等价于CLass(C是没有Class这个东西的)。这里我们又引出了一个很大的话题,面向过程和面向对象的区别。这里我们只选其中很小的一部分来说。 面向过程认为,数据和数据的操作是分开的。(当然面向过程也可以刻意的实现把数据和数据的操作集合到一起) 面向对象认为,数据和数据的操作是一个整体,不应该分开的。 这样面向对象就和面向过程有了很大的冲突。这个冲突其实引发了struct的C和C++的差异性。 C++中的struct是可以包含函数的,可以拥有构造函数,析构函数同样拥有继承等能力。这个时候。。很多人就会疑惑?那struct和CLASS不就一样了吗? 对struct和class的确差别不大。从使用上差别不大。使用上的差别唯一的就是默认访问类型不一样struct默认公有,class默认私有。(改了- -!手误。。。) 肯定就有朋友会问,平常我们都不会依赖于默认啦,不同的编译器可能默认方式都不一样的。照这个思维不就是完全没区别了。对我说的很大区别,其实针对的是思想上并非使用上。 第一:struct是继承于C但又要适合于面向对象。所以struct是丢也不是,留下又多余的尴尬局面。 第二:C++中的struct已经被扩展,已经不再是C时代的struct 那么最大的思想差别是啥呢?我也说不清楚。思想的东西我觉得,是要靠感悟的,可能从我嘴来说出来的思想,在你眼里可能是狗屁不通,甚至是一堆臭鸡蛋。所以下面我说一个我认为的C++中struct思想。 在面向对象横行的时代。相信大家都对几个面向对象词语有很深的认识,对象,类,接口,继承等等。 但是大家留心会发现,C++里面没有“接口”这个东西。说起接口这个东西,就不能不说java了,在JAVA里是不允许多继承的,但是能实现继承多个接口。但是C++却是允许实现多继承,那么如果C++里出现接口这个东西,最后的结果也会变成多余。 所以我觉得“接口”其实已经在面向对象里形成了一种文化。但是作为编程界翘楚的C++却没有“接口”这样东西。人的思维是强大的,例如MS的做法就是将struct当成了接口来使用。 "我觉得C++中的struct和class区别不是在于使用,不在于语法糖,而是在于思想,在于构架约定等方面。" |
从以上我们可以知道,使用struct是为了和Java的面向对象编程思想保持一致,也就是说其实用abstract class也是一样的效果,但是interface看起来更像面向对象一些。
接口使用方法实例:
#include <iostream> using namespace std; #include <objbase.h> // Define interface. /* 输出一个字符串 */ void trace(const char* pMsg) { cout << pMsg << endl; } /* IX和IY为普通接口(非COM接口),其实它们是抽象基类 */ interface IX { virtual void __stdcall Fx1() = 0 ; virtual void __stdcall Fx2() = 0 ; }; interface IY { virtual void __stdcall Fy1() = 0 ; virtual void __stdcall Fy2() = 0 ; }; /* 接口的实现,这里用了多重继承 */ class CA : public IX, public IY { public: // Implement interface IX. virtual void __stdcall Fx1() {cout << "CA::Fx1" << endl;} virtual void __stdcall Fx2() {cout << "CA::Fx2" << endl;} // Implement interface IY. virtual void __stdcall Fy1() {cout << "CA::Fy1" << endl;} virtual void __stdcall Fy2() {cout << "CA::Fy2" << endl;} }; /* 客户(在这里是一个主函数) */ int main() { trace("Client: Create an instance of the component."); CA* pA = new CA; // Get an IX pointer. IX* pIX = pA; trace("Client: Use the IX interface."); pIX->Fx1(); pIX->Fx2(); // Get an IY pointer. IY* pIY = pA; trace("Client: Use the IY interface."); pIY->Fy1(); pIY->Fy2(); trace("Client: Delete the component."); delete pA; return 0; } |
虽然C++可以直接操作和使用实例数据,但COM组件绝不会访问任何实例数据,在COM中,对一个组件的访问只能通过函数完成,而绝不能直接通过变量.这一点同我们对COM组件的定义是相符的.纯抽象基类只有虚拟函数,而没有任何实例数据.
对于COM来说,接口是一个包含一个函数指针数组的内存结构。
接口是由没有实现细节的虚线基类实现的。
编码约定
在所有的前面都加有一个字母I, 如:IX表示的“接口X”。
而在类名称的前面所加的前缀则为C, 如CA表示“类A”。
Microsoft Win32软件开发工具(SDK)中OBJBASE.H头文件的定义:#define interface struct
使用struct的原因在于struct的成员将自动具有我公有的属性,因此不需要另外定义中加上public关键字。
标准调用
Microsoft平台上COM接口所提供的所有函数使用的均是标准的调用约定.参数数目可变的函数使用的则是C调用约定.一般人们希望接口的实现使用这些约定.但要说明的是这并不是COM的绝对需要.
在WINDEF.H中pascal的定义如下:
#define pascal __stdcall
如果读者认为将pascal这个词放在代码中会让人莫名其妙,那么可以使用OBJBASE.H中所定义的如下宏:
#define STDMEFHODCALLTYPE __stdcall
类并非组件
用C++开发组件时不一定非用类不可。组件也可以用C来实现。一个组也可以由多个类来实现。
接口并非总是继承的
COM没有要求实现某个接口的类必须从那个接口继承,这是客户并不需要了解COM组件的继承关系。对接口的继承只不过是一种实现细节而已。
多重接口及多重继承
一个接口是一个函数集合,一个组件则是一个接口集,而一个系统则是一系列组件的集合。
接口不变性
一旦分布了一个接口,那么它将永远保持不变。当对组件进行升级时,一般不会修改已有的接口,面是加入一些新接口。
命名冲突
对于一个支持多个接口的组件,接口函数的名字出现冲突是经常会遇到的。这些种情况下,改变某个发生冲突的函数名称即可。COM对此不关心。COM接口是一个二进制标准,客户同接口的连接并不是通过其名称或其成员函数的名称完成的,而是通过它在表示它的内存块的位完成的。
解决命名冲突的另外一种 方法是不使用多重继承。
实现组件的类并不需要继承每一个接口,而可以使用指向实现某些接口的类的指针。
接口名称之间出现冲突的情况也是可能的。如果在接口和函数名称的前面加上公司名称或产品名称可以减少此种 可能性。
多态
多态指的是可以按同一种方式来处理不同的对象。若两个不同的组件支持同一接口,那么客户将可以使用相同的代码一处理其中的任何一个组件。就是说,客户可以按照相同的方式来处理不同的组件。
虚拟函数表
当定义一个纯抽象类时,所定义的实际上是一个内存块的结构.纯抽象类所有实现都是一些具有相同的基本结构的内存.
如下定义一个抽象基类。内存结构如图2-4所示:
interface IX
{
virtual void __stdcall Fx1() = 0 ;
virtual void __stdcall Fx2() = 0 ;
virtual void __stdcall Fx3() = 0 ;
virtual void __stdcall Fx4() = 0 ;
};
定义一个抽象基类也就是定义了相应的内存结构。但些内存只在派生在中实现些抽象基类时才会被分配。当派生类继承一个抽象基类时,它将继承此内存结构。
似乎是一个的偶然的巧合,COM接口的内存结构同C++编译器为抽象基类所生成的内存结构是相同的.因此可以使用抽象基类来定义COM接口.
对于一个COM接口还有其他一些需求.例如,所有的COM接口都必须继承一个名为Iunknown的接口.
Vtbl指针及实例数据
Vtbl指针在由抽象基类函数指针到函数的过程中增加了一个额外的级别。这带了很大的灵活性。
实现抽象基类的类可能会将特定于实例的信息同vtbl一块保存。如下IX的实现类CA:
class CA : public IX
{
public:
virtual void __stdcall Fx1(){cout << "CA::Fx1" << endl;}
virtual void __stdcall Fx2(){cout << m_Fx2 << endl;}
virtual void __stdcall Fx3(){cout << m_Fx3 << endl;}
virtual void __stdcall Fx4(){cout << m_Fx4 << endl;}
CA(double d):
m_Fx2(d*d),m_Fx3(d*d*d), m_Fx4(d*d*d*d)
{
}
double m_Fx2;
double m_Fx3;
double m_Fx4;
};
多重实例
在C++中同一个类的不同实例可以共享同一个vtbl。如下:
int main()
{
CA* pA1 = new CA(4.3);
CA* pA2 = new CA(5.1);
...
...
}
虽然COM组件可以使用vtbl指针来共享vtbl,但这一点并不是必需的。COM组件的每个实例中已有一个不同的vtbl
不同的类,相同的vtbl
接口的真正威力在于继承此接口的所有类均可以被客户按同一方式进行处理。
例子:
class CB : public IX
{
public:
// implementatio inerface IX.
virtual void __stdcall Fx1(){cout << "CB::Fx1" << endl;}
virtual void __stdcall Fx2(){cout << "CB::Fx2" << endl;}
virtual void __stdcall Fx3(){cout << "CB::Fx3" << endl;}
virtual void __stdcall Fx4(){cout << "CB::Fx4" << endl;}
};
void foo(IX* pIX)
{
pIX->Fx1();
pIX->Fx2();
}
int main()
{
CA* pA = new CA(4.3);
CB* pB = new CB;
IX* pIX = pA;
foo(pIX);
pIX = pB;
foo(pIX);
}
从上例中,我们将CA和CB都当成是IX接口来作用。这也是多态的一个例子。
从上图可以看出,CA 和 CB 分别具有不同的实例数据、vtbl以及实现。但是因其具有相同的而可以按相同的方式来访问。
interface接口实例相关推荐
- 接口实例(C#,IShape)【C#】
接口实例(C#,IShape) 题目描述 接口实例.接口和类如下图所示,根据给出代码,补写缺失的代码,然后在Program类的静态Main方法中验证所实现的类. using System; names ...
- java 接口函数_Java函数式接口Supplier接口实例详解
这篇文章主要介绍了Java函数式接口Supplier接口实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 JDK提供了大量常用的函数式接口以丰 ...
- Golang interface 接口详细原理和使用技巧
文章目录 Golang interface 接口详细原理和使用技巧 一.Go interface 介绍 interface 在 Go 中的重要性说明 interface 的特性 interface 接 ...
- java supplier接口_Java函数式接口Supplier接口实例详解
这篇文章主要介绍了Java函数式接口Supplier接口实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 JDK提供了大量常用的函数式接口以丰 ...
- 12、Interface (接口)克隆
文章目录 (一)Interface Note 1.概念 2.基本语法 声明接口 继承接口 实现接口 3.特点 4.抽象类与接口的区别 共同点 区别 选择 5.克隆 附:抽象类 PK 接口 (二)Int ...
- Go语言-Go interface 接口的最佳实践
文章目录 Go语言-Go 接口的最佳实践 什么是Golang中的interface 编写接口的最佳实践 1. 保持interfaces足够小 2. Interfaces Should Have No ...
- java枚举类型原理_Java枚举类接口实例原理解析
这篇文章主要介绍了Java枚举类接口实例原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 枚举类可以实现一个或多个接口.与普通类实现接口完全一 ...
- php magento 开发,magento2 开发Api接口实例
magento2 开发Api接口实例 新建一个模块 第一步先创建module.xml初始化模块 模块配置 – etc/module.xml 然后新建Registration 注册模块 – regist ...
- abstract(抽象类)与interface(接口)的区别
文章目录 前言 一.abstract(抽象类) 1.用abstract关键字修饰方法 1.用abstract关键字修饰类 二.interface(接口) 总结 前言 abstract(抽象类)与int ...
最新文章
- [转]ORA-01555错误总结(二)
- flutter android 权限,Flutter permission_handler 权限插件的使用详解
- linux 查看所有存在的线程
- 网上赚钱最快的方法 干什么能挣钱快
- 软件工程标准与软件文档
- 全球搜索引擎Top10 可惜很多人只用过第四个
- Kylin启动报错 ERROR: Check hive‘s usability failed, please check the status of your cluster
- ns手柄pc驱动_支持amiibo和体感!switch游戏手柄莱仕达天弓NS体验
- 软件设计师证书重要吗?
- vue+websocket+express+mongodb实战项目(实时聊天)(一)
- 下载pyboard的flash中的驱动程序_驱动人生下载-驱动人生绿色最新下载正式版
- git 移除项目版本控制_Git - 关于版本控制
- Linux下十大命令行下载工具
- 【NLG】(六)文本生成评价指标—— ROUGE原理及代码示例
- 基于Html+Css+javascript的动漫网站
- RabbitMQ管理平台功能说明文档
- Xposed模块开发教程,该篇讲解通俗易懂,所以转发
- 如何进行在线教育app开发
- 测肺活量可以用手机 SpiroSmart将音频转为风量
- 洛谷P1166 打保龄球(模拟)