interface强制转换的有趣现象 ( 积分: 100 )

  • 主题发起人 主题发起人 张鸿林
  • 开始时间 开始时间

张鸿林

Unregistered / Unconfirmed
GUEST, unregistred user!
定义两个接口类型:
IIntf1=interface
['{85460100-EB0D-11D9-8395-BA555218190B}']
procedure I1Func1(p1:string);
procedure I1Func2(p1,p2:string);
end;

IIntf2=interface
['{85460101-EB0D-11D9-8395-BA555218190B}']
procedure I2Func1(p1:integer);
procedure I2Func2(p1,p2:integer);
procedure I2Func3;
end;

定义一个类实现这两个接口:

TIntfObj=class(TInterfacedObject,IIntf1,IIntf2)
procedure I1Func1(p1:string);
procedure I1Func2(p1,p2:string);
procedure I2Func1(p1:integer);
procedure I2Func2(p1,p2:integer);
procedure I2Func3;
end;
TIntfObj 方法的实现代码大致如下(把方法名show出来):
procedure TIntfObj.I1Func1(p1: string);
begin
// ShowMessage('I1Func1:'+p1);
ShowMessage('I1Func1');
end;
在客户程序定义这个类为IIntf1:
var FIntfObj:IIntf1;
创建:
FIntfObj:=TIntfObj.Create as IIntf1;

FIntfObj.I1Func1(...) //这样调用当然没有问题
请看下面:

IIntf2(FIntfObj).I2Func1(...) 将会调用 IIntf1.I1Func1方法
IIntf2(FIntfObj).I2Func2(...) 将会调用 IIntf1.I1Func2方法
IIntf2(FIntfObj).I2Func3(...) 将会出错
结论:
当接口被强制转换为与声明的类型不同时,仍然是原接口的方法被调用,且,具体调用
哪个接口方法与方法名无关,与方法序号有关,换句话说,按方法在接口声明中的序号调用
这样的调用,如果方法体中忽略方法参数(不访问方法参数),系统不会出错,但如果访问
了方法参数,将会出现不可预料的问题
 
定义两个接口类型:
IIntf1=interface
['{85460100-EB0D-11D9-8395-BA555218190B}']
procedure I1Func1(p1:string);
procedure I1Func2(p1,p2:string);
end;

IIntf2=interface
['{85460101-EB0D-11D9-8395-BA555218190B}']
procedure I2Func1(p1:integer);
procedure I2Func2(p1,p2:integer);
procedure I2Func3;
end;

定义一个类实现这两个接口:

TIntfObj=class(TInterfacedObject,IIntf1,IIntf2)
procedure I1Func1(p1:string);
procedure I1Func2(p1,p2:string);
procedure I2Func1(p1:integer);
procedure I2Func2(p1,p2:integer);
procedure I2Func3;
end;
TIntfObj 方法的实现代码大致如下(把方法名show出来):
procedure TIntfObj.I1Func1(p1: string);
begin
// ShowMessage('I1Func1:'+p1);
ShowMessage('I1Func1');
end;
在客户程序定义这个类为IIntf1:
var FIntfObj:IIntf1;
创建:
FIntfObj:=TIntfObj.Create as IIntf1;

FIntfObj.I1Func1(...) //这样调用当然没有问题
请看下面:

IIntf2(FIntfObj).I2Func1(...) 将会调用 IIntf1.I1Func1方法
IIntf2(FIntfObj).I2Func2(...) 将会调用 IIntf1.I1Func2方法
IIntf2(FIntfObj).I2Func3(...) 将会出错
结论:
当接口被强制转换为与声明的类型不同时,仍然是原接口的方法被调用,且,具体调用
哪个接口方法与方法名无关,与方法序号有关,换句话说,按方法在接口声明中的序号调用
这样的调用,如果方法体中忽略方法参数(不访问方法参数),系统不会出错,但如果访问
了方法参数,将会出现不可预料的问题
 
哦,有意思,以前没有注意到;

我是想问一下为什么要用这种调用方式??
IIntf2(FIntfObj).I2Func1(...) 将会调用 IIntf1.I1Func1方法
IIntf2(FIntfObj).I2Func2(...) 将会调用 IIntf1.I1Func2方法
IIntf2(FIntfObj).I2Func3(...) 将会出错
还是申明一个接口变量,进行赋值后在调用,应为在赋值时编译器会帮你进行类型转换
 
用以下这样调用即可:
(FIntfObj as IIntf2).I2Func1(...);

当使用as操作符时,Delphi会帮你调用QueryInterface以确定你的FIntfObj是否支持IIntf2接口,如果支持则返回一个IIntf2类型的接口指针;而单纯的强制类型转换为只是简单的把FIntfObj看做是IIntf2类型的接口变量,此时调用的方法当然是原来的IIntf1接口的方法。

当然上面的方法在FIntfObj不支持IIntf2接口时会出错,因此最好如下处理:
var
I2: IIntf2;

I2 := FIntfObj as IIntf2;
if Assigned(I2) then
begin
//Call method of IIntf2
end.
 
不错,第一次见,跟高手学习真是长见识。
 
多人接受答案了。
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
I
回复
0
查看
724
import
I
后退
顶部