Excel 我可以对任何对象进行强制转换';什么是默认接口?

Excel 我可以对任何对象进行强制转换';什么是默认接口?,excel,vba,interface,reference,Excel,Vba,Interface,Reference,我知道在VBA中,所有类都公开一个默认接口(这只是类模块的名称)。您还可以让他们实现另一个自定义界面;为类提供一些属性,这些属性从自定义接口的角度来看是可见的,但从默认接口看不到 我有一个方法,它需要实现某个接口的类 Public Sub doStuff(ByVal item As ICustomInterface) 像 Dim a As New Class1 'Implements ICustomInterface Dim b As New Class2 'Implements ICusto

我知道在VBA中,所有类都公开一个默认接口(这只是类模块的名称)。您还可以让他们
实现另一个自定义界面
;为类提供一些属性,这些属性从自定义接口的角度来看是可见的,但从默认接口看不到

我有一个方法,它需要实现某个接口的类

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
的引用,并将新引用存储在
变量中。我认为这个过程叫做向下投射

我的问题是
doStuff
调用的方法需要传递item的默认接口,而不是自定义接口。


为了演示,我们可以使用
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

但我更喜欢在我的函数签名中检查类型,然后在需要时向上转换回默认界面的工作流程只需先转换为IUnknown:

    Dim objectUpCast As Object
    Dim iUnk As IUnknown
    Set iUnk = downCast
    Set objectUpCast = iUnk
编辑

所有VB接口都是双接口,这意味着所有接口都源自IDispatch,而IDispatch又源自IUnknown

请注意,对象数据类型代表IDispatch接口

在您的示例中:

Dim strictUpCast As Class1
Set strictUpCast = downCast
Dim objectUpCast As Object
Set objectUpCast = downCast
第二行调用QueryInterface,询问Class1接口,如预期的那样

在您的另一个示例中:

Dim strictUpCast As Class1
Set strictUpCast = downCast
Dim objectUpCast As Object
Set objectUpCast = downCast
在第二行,可能会发生2件事:

  • 如果变量(downCast)指向双接口(从IDispatch派生的接口),那么VB只会增加引用计数(从而返回与downCast相同的接口)
  • 如果变量指向自定义接口(从IUnknown派生),则VB调用QueryInterface并请求IDispatch接口
  • 转换到IUnknown接口(OLE自动化库的一部分)时:

    iUnk变量指向自定义接口(仅从IUnknown派生)

    这涉及到:

    Dim objectUpCast As Object
    Set objectUpCast = iUnk
    

    其中,在第二行,VB调用QueryInterface并请求IDispatch接口,因为变量(右侧)指向一个自定义接口(IUnknown本身不是从IDispatch派生的)。IDispatch接口知道默认接口,这就是返回的

    是的,就这样!我想知道,你能解释一下这是怎么回事吗?据我所知,VBA中定义的每个接口/类都扩展了IUnknown,因此可以将其转换为IUnknown。但为什么对IUnknown的强制转换然后对对象的强制转换会跳转到默认接口。如果一个接口已经扩展了IUnknown,那么将该接口强制转换到IUnknown不是一个有效的禁止操作吗?(很明显这是可行的,但我很想知道原因:)@Greedo我已经编辑了答案,包括一个解释