接口引用 如何从一个接口变量取得其接口类型
2011-07-23 17:09
459 查看
http://blog.sina.com.cn/s/blog_5d10e5410100hjna.html
近期在写一个类pascal解释器,对borland的RTTI机制进行了一番学习,了解了borland的RTTI机制,但本人水平有限,在学习有关接口的RTTI过程中,遇到了些无法解释的问题,在这里提出来,大家共同探讨。
首先说明“接口引用”这个概念在delphi中也许不存在,是我相对于“类引用”提出来的。我们知道在delphi 中有类引用的概念,定义方式如TClass = class of TObject,其实质是指向类RTTI的一个指针,我们可以用这个类引用实现好多动态功能。可接口就比较特殊,虽然定义语法和类定义类似,但只是一个空壳,需要通过某个具体的类来实现。虽然接口是一个空壳,但是这个空壳也有RTTI信息,可以通过TypeInfo函数得到。
在VCL中其实也运用了好多 “接口引用”的概念,比如IInterface中的QueryInterface函数,查询接口支持的函数supports等,但在delphi并没有类似“ Interface of Interface”这样的句法来定义一个接口引用,而是使用一个TGUID来完成接口引用的功能。TGUID其实被定义为一个结构类型,delphi的编译器知道如何把TGUID类型转换成接口引用来使用,但对开发者来说却是不公布的。比如:
var
Obj : TObject;
m:TComponent;
ClassRef: TClass;
Intf: IInterface;
IID: TGUID;
begin
obj := TComponent.Create(nil);
ClassRef := obj.ClassType; //对于类变量,我们可以用类函数classType来取得它的类类型。
m := obj as TComponent;
Intf := m; //把M赋给接口变量,因为TComponent实现了IInterface接口。
{
IID := ? intf ;//无法取得接口变量的接口类型?!
}
end;
归结起来,写一个函数,取得一个接口变量的接口类型(GUID):
function GetIntfGUID(AIntf: IInterface):TGUID;
begin
Result := ;//如何实现?和各位继续探讨
end;
解释:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
IFirstIntf=interface
['{64C25101-E002-40EF-92DC-F0DFBF876B1C}']
function GetName:string;
function GetGUID:string;
function GetIntfGUID(AIntf: IInterface):TGUID;
end;
TFirstIntfClass=class(TInterfacedObject, IFirstIntf)
//IFirstIntf
function GetName:string;
function GetGUID:string;
function GetIntfGUID(AIntf: IInterface):TGUID;
end;
type
TForm1 = class(TForm)
btnSayHello: TButton;
btnGUIID: TButton;
lst1: TListBox;
btnAllGUID: TButton;
btnIntfaceToGUID: TButton;
procedure btnSayHelloClick(Sender: TObject);
procedure btnGUIIDClick(Sender: TObject);
procedure btnAllGUIDClick(Sender: TObject);
procedure btnIntfaceToGUIDClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
function TFirstIntfClass.GetName;
begin
Result:='Hello World';
end;
procedure TForm1.btnSayHelloClick(Sender: TObject);
var
FirstIntfClass:TFirstIntfClass;
FirstIntf:IFirstIntf;
begin
FirstIntfClass:=TFirstIntfClass.Create;
try
FirstIntf:=FirstIntfClass;
ShowMessage(FirstIntf.GetName);
finally
FirstIntf:=nil;
end;
end;
function TFirstIntfClass.GetGUID;
begin
if self.GetInterfaceTable.EntryCount>0 then
Result:=GUIDToString(Self.GetInterfaceTable.entries[0].iid)
end;
procedure TForm1.btnGUIIDClick(Sender: TObject);
var
FirstIntfClass:TFirstIntfClass;
FirstIntf:IFirstIntf;
begin
FirstIntfClass:=TFirstIntfClass.Create;
try
FirstIntf:=FirstIntfClass;
ShowMessage(FirstIntf.GetGUID);
finally
FirstIntf:=nil;
end;
end;
procedure TForm1.btnAllGUIDClick(Sender: TObject);
var
I:Integer;
FirstIntfClass:TFirstIntfClass;
FirstIntf:IFirstIntf;
begin
FirstIntfClass:=TFirstIntfClass.Create;
for I:= 0 to FirstIntfClass.GetInterfaceTable.EntryCount-1 do begin
lst1.Items.Add(GUIDToString(FirstIntfClass.GetInterfaceTable.Entries[I].IID));
end;
FirstIntfClass.Free;
end;
function TFirstIntfClass.GetIntfGUID(AIntf: IInterface):TGUID;
var
I:Integer;
FirstIntfClass:TFirstIntfClass;
begin
FirstIntfClass:=TFirstIntfClass.Create;
for I:=0 to FirstIntfClass.getInterfaceTable.EntryCount-1 do
if FirstIntfClass.GetInterface(FirstIntfClass.getInterfaceTable.Entries[I].IID, AIntf) then begin
Result:=FirstIntfClass.getInterfaceTable.Entries[I].IID;
Exit;
end;
FirstIntfClass.Free;
end;
procedure TForm1.btnIntfaceToGUIDClick(Sender: TObject);
var
FirstIntfClass:TFirstIntfClass;
FirstIntf:IFirstIntf;
GUID:TGUID;
begin
GUID:=FirstIntfClass.GetIntfGUID(FirstIntf);
if GUID.D1>0 then
ShowMessage(GUIDToString(GUID));
end;
end.
近期在写一个类pascal解释器,对borland的RTTI机制进行了一番学习,了解了borland的RTTI机制,但本人水平有限,在学习有关接口的RTTI过程中,遇到了些无法解释的问题,在这里提出来,大家共同探讨。
首先说明“接口引用”这个概念在delphi中也许不存在,是我相对于“类引用”提出来的。我们知道在delphi 中有类引用的概念,定义方式如TClass = class of TObject,其实质是指向类RTTI的一个指针,我们可以用这个类引用实现好多动态功能。可接口就比较特殊,虽然定义语法和类定义类似,但只是一个空壳,需要通过某个具体的类来实现。虽然接口是一个空壳,但是这个空壳也有RTTI信息,可以通过TypeInfo函数得到。
在VCL中其实也运用了好多 “接口引用”的概念,比如IInterface中的QueryInterface函数,查询接口支持的函数supports等,但在delphi并没有类似“ Interface of Interface”这样的句法来定义一个接口引用,而是使用一个TGUID来完成接口引用的功能。TGUID其实被定义为一个结构类型,delphi的编译器知道如何把TGUID类型转换成接口引用来使用,但对开发者来说却是不公布的。比如:
var
Obj : TObject;
m:TComponent;
ClassRef: TClass;
Intf: IInterface;
IID: TGUID;
begin
obj := TComponent.Create(nil);
ClassRef := obj.ClassType; //对于类变量,我们可以用类函数classType来取得它的类类型。
m := obj as TComponent;
Intf := m; //把M赋给接口变量,因为TComponent实现了IInterface接口。
{
IID := ? intf ;//无法取得接口变量的接口类型?!
}
end;
归结起来,写一个函数,取得一个接口变量的接口类型(GUID):
function GetIntfGUID(AIntf: IInterface):TGUID;
begin
Result := ;//如何实现?和各位继续探讨
end;
解释:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
IFirstIntf=interface
['{64C25101-E002-40EF-92DC-F0DFBF876B1C}']
function GetName:string;
function GetGUID:string;
function GetIntfGUID(AIntf: IInterface):TGUID;
end;
TFirstIntfClass=class(TInterfacedObject, IFirstIntf)
//IFirstIntf
function GetName:string;
function GetGUID:string;
function GetIntfGUID(AIntf: IInterface):TGUID;
end;
type
TForm1 = class(TForm)
btnSayHello: TButton;
btnGUIID: TButton;
lst1: TListBox;
btnAllGUID: TButton;
btnIntfaceToGUID: TButton;
procedure btnSayHelloClick(Sender: TObject);
procedure btnGUIIDClick(Sender: TObject);
procedure btnAllGUIDClick(Sender: TObject);
procedure btnIntfaceToGUIDClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
function TFirstIntfClass.GetName;
begin
Result:='Hello World';
end;
procedure TForm1.btnSayHelloClick(Sender: TObject);
var
FirstIntfClass:TFirstIntfClass;
FirstIntf:IFirstIntf;
begin
FirstIntfClass:=TFirstIntfClass.Create;
try
FirstIntf:=FirstIntfClass;
ShowMessage(FirstIntf.GetName);
finally
FirstIntf:=nil;
end;
end;
function TFirstIntfClass.GetGUID;
begin
if self.GetInterfaceTable.EntryCount>0 then
Result:=GUIDToString(Self.GetInterfaceTable.entries[0].iid)
end;
procedure TForm1.btnGUIIDClick(Sender: TObject);
var
FirstIntfClass:TFirstIntfClass;
FirstIntf:IFirstIntf;
begin
FirstIntfClass:=TFirstIntfClass.Create;
try
FirstIntf:=FirstIntfClass;
ShowMessage(FirstIntf.GetGUID);
finally
FirstIntf:=nil;
end;
end;
procedure TForm1.btnAllGUIDClick(Sender: TObject);
var
I:Integer;
FirstIntfClass:TFirstIntfClass;
FirstIntf:IFirstIntf;
begin
FirstIntfClass:=TFirstIntfClass.Create;
for I:= 0 to FirstIntfClass.GetInterfaceTable.EntryCount-1 do begin
lst1.Items.Add(GUIDToString(FirstIntfClass.GetInterfaceTable.Entries[I].IID));
end;
FirstIntfClass.Free;
end;
function TFirstIntfClass.GetIntfGUID(AIntf: IInterface):TGUID;
var
I:Integer;
FirstIntfClass:TFirstIntfClass;
begin
FirstIntfClass:=TFirstIntfClass.Create;
for I:=0 to FirstIntfClass.getInterfaceTable.EntryCount-1 do
if FirstIntfClass.GetInterface(FirstIntfClass.getInterfaceTable.Entries[I].IID, AIntf) then begin
Result:=FirstIntfClass.getInterfaceTable.Entries[I].IID;
Exit;
end;
FirstIntfClass.Free;
end;
procedure TForm1.btnIntfaceToGUIDClick(Sender: TObject);
var
FirstIntfClass:TFirstIntfClass;
FirstIntf:IFirstIntf;
GUID:TGUID;
begin
GUID:=FirstIntfClass.GetIntfGUID(FirstIntf);
if GUID.D1>0 then
ShowMessage(GUIDToString(GUID));
end;
end.
相关文章推荐
- C语言extern引用AT&T汇编中的变量,任意转换类型
- 成员变量中的引用类型为null有意义时如何比较值是否相等
- 定义接口类型的引用变量有什么好处?
- 定义接口类型的引用变量有什么好处?
- (转)定义接口类型的引用变量有什么好处?
- 定义接口类型的引用变量有什么好处?
- Java Lambda(语言篇——lambda,方法引用,目标类型,默认方法,函数接口,变量捕获)
- 【Unity&C#&数组】如何创建一个存放任何类型变量的数组
- foreach的语句格式:for(元素类型t 元素变量x : 遍历对象obj)
- java :引用类型的转换  方法重载和重写  构造函数 修饰符
- 如何初始化引用类型的成员变量
- 不能将类型为‘std::string&’的非 const 引用初始化为类型为‘const char*’的临时变量
- C++ 成员变量为引用类型和const类型,如何赋值
- Java接口中的变量和方法默认的类型<转>
- 【JAVA】Java性能优化,基本类型 vs 引用类型
- 如何使用引用类型来改变变量的值
- [c&cpp]const char* 和const char []在代码中如何识别各自类型
- 多个引用类型的变量“引用”同一个对象意味着什么
- 未能找到类型或命名空间名称"bll"(是否缺少using指令或程序集引用)
- 2018/01/08JAVA 基础 / 接口与继承/Java关键词:变量引用 super 调用父类对象方法/构造方法【或者访问父类对象属性】的方式归纳