我了解在VBA中,所有类都公开一个默认接口(这只是类模块的名称)。您还可以使它们Implement
成为另一个自定义界面;为该类提供一些属性,这些属性从自定义界面的角度是可见的,但是从默认界面的角度是不可见的。
我有一个方法,它期望实现特定接口的类
Public Sub doStuff(ByVal item As ICustomInterface)
称呼为
Dim a As New Class1 'Implements ICustomInterface
Dim b As New Class2 'Implements ICustomInterface too
doStuff a
doStuff b
doStuff New Collection 'raises "runtime error 13 - type mismatch" as Collection doesn't implement ICustomInterface
如果我正确理解,则在向该方法提供对象的实例时,通过传递对该对象默认接口的引用,VBA会查询该对象实例以生成对该对象的ICustomInterface
的引用,并将新引用存储在item
变量中。我认为这个过程称为向下转换。
我的问题是doStuff
调用了一种方法,要求传递商品的默认界面,不是自定义界面。
为了演示,我们可以使用ObjPtr
来标识所指向的接口:
Dim implementation As Object
Dim defaultCast As Class1 'implements ICustomInterface
Dim downCast As ICustomInterface
Set implementation = New Class1 'or Class2 - store reference to default interface in variable
'1) Check if implementation indeed points to default interface
Set defaultCast = implementation
Debug.Assert ObjPtr(defaultCast) = ObjPtr(implementation) 'fine
'2) Check if down-casting gives different interface
Set downCast = implementation
Debug.Assert ObjPtr(downCast) <> ObjPtr(implementation) 'fine
'4) Check if casting from ICustomInterface to Object reverts to default interface
Dim objectUpCast As Object
Set objectUpCast = downCast
Debug.Assert ObjPtr(objectUpCast) = ObjPtr(implementation) 'fails :(
Debug.Assert ObjPtr(objectUpCast) = ObjPtr(downCast) 'succeeds - not what I want
'3) Check if casting from ICustomInterface to Class1 reverts to Class1's default interface
Dim strictUpCast As Class1
Set strictUpCast = downCast
Debug.Assert ObjPtr(strictUpCast) = ObjPtr(implementation) 'fine - but won't work if I Set implementation = New Class2
'/some other implementation of the ICustomInterface
第三个选项;使用自定义界面并恢复为默认界面是我想要的
我希望在函数签名中输入安全性。我可以显式使用自定义界面-这是我当前的解决方法
Public Sub doStuff(ByVal item As Object) 'receive default interface - or at least whatever interface is provided
Dim downCast As ICustomInterface
Set downCast = item
'work with downCast as necessary
'... later pass default interface "item" to other sub
End Sub
但是我更喜欢在我的函数签名中检查类型,然后在需要时向上投射回默认界面的工作流程
答案 0 :(得分:1)
首先强制转换为IUnknown:
Dim objectUpCast As Object
Dim iUnk As IUnknown
Set iUnk = downCast
Set objectUpCast = iUnk
修改
所有VB接口都是双重接口,这意味着所有接口均来自IDispatch,而IDispatch又来自IUnknown。
请注意,Object数据类型代表IDispatch接口。
在您的示例中:
Dim strictUpCast As Class1
Set strictUpCast = downCast
第二行调用QueryInterface,按预期方式请求Class1接口。
在另一个示例中:
Dim objectUpCast As Object
Set objectUpCast = downCast
在第二行中会发生两种情况:
强制转换为IUnknown接口(OLE自动化库的一部分)时:
Dim iUnk As IUnknown
Set iUnk = downCast
iUnk变量指向自定义界面(仅来自IUnknown)。
这将达到:
Dim objectUpCast As Object
Set objectUpCast = iUnk
在第二行中,VB调用QueryInterface并请求IDispatch接口,因为变量(右侧)指向自定义接口(IUnknown本身,它不是从IDispatch派生的)。 IDispatch接口知道默认接口,这就是返回的