VBA继承,类似于super的模拟

22
例如我有一个类A实现了类B。
---类A---
implements B
public sub B_do()
end sub

--类别 B--

public sub do()
end sub
我如何从A中调用do()方法?(super.do())那么,我如何为两个类定义一些共同的变量?现在,我只能继承函数、子和属性...
添加:同样的问题请参考http://social.msdn.microsoft.com/Forums/en-US/vbgeneral/thread/5a83d794-3da1-466a-83d3-5d2eb0a054b2 添加:无法跨类层次结构共享变量。您应该实现属性(与函数相同的方式)。
3个回答

28
通常在VBA中实现此功能的方法是让A包含B的一个实例并使A实现B的接口,然后将对A的B接口的调用委托给内部的B。
这是老旧内容,但请参阅Visual Studio 6.0程序员指南:

http://msdn.microsoft.com/en-us/library/aa716285(VS.60).aspx

有一章关于“代码重用的多种面孔”,描述了这个惯例:

http://msdn.microsoft.com/en-us/library/aa240846(v=VS.60).aspx

微软的描述是:

除了实现抽象接口外,您还可以通过实现普通类的接口,然后有选择地委托给一个隐藏类的实例来重用您的代码。

这意味着实现继承需要大量显式的委托方法。甚至有一章小标题为:"这不会很烦吗?"。这也是为什么在VBA中使用面向对象编程非常麻烦的原因之一(商标)...

无法在评论中放入编辑答案:

回答您在评论中提出的问题,嗯,A B。当您让A实现B的接口时,实质上是说您可以将A的实例视为实际类型为B的实例。 在VBA中,您可以声明一个类型为B的变量,然后将其设置为A的实例。当您像调用B一样调用它时,VBA将知道该怎么做:

Dim usedAsB as B
Dim anA as A

Set anA = New A
Set usedAsB = anA    'fine since A implements B

usedAsB.something()    'will call B_something() defined in class A

就你在调试窗口看到的内容而言,我不知道它为什么会出现那样。至于强制委托,我不确定你的意思是什么。VBA会自动将对B接口的调用分派到A类中正确的方法上。如果你指的是以上述方式自动生成继承B实现的代码,我不知道有这样的东西适用于VBA。我认为各种VB6的“专业”版本可以做到这一点,但我从未使用过VB6,所以不确定。

谢谢!您知道一些关于在VBA中精确实例化类的来源吗?在调试中,我看到类A有一个类型为B的字段。因此,在互联网上某个地方,我发现类型为A的对象实际上是类型为B的对象(通过强制委托)。 - nikaan
@Nikita,我建议你阅读程序员指南中涉及“对象编程”的其他章节。至于另一个问题,我将编辑我的答案,因为它可能不适合在评论中回答。所以请稍等几分钟,在那里查看我的回答... - jtolle

6

这是我长期以来使用的一种方式,通过接口模拟抽象类。

'class module: IBase
'We define a base interface
'
Sub go(): End Sub

Sub gogo(): End Sub

现在让我们定义其他类,从抽象类'B'开始。
'
'class module: B
'
Implements IBase

'Daughter classes should implement 'go'
'Note that the method is 'Public'
Public Sub go(): End Sub

'Let's agree that every daughter class implements the method
'abstract 'super' that returns the IBase interface
Public Property Get super() As IBase: End Property

'
'The signature of other abstract methods can be stated here
'
'Public Sub goGoChild(): End Sub
'Public Function goGoGoChild2(): End Function
'

'
'Note that the methods are accessible through the IBase interface
'
Private Sub IBase_go()
    Debug.Print "B: super.go()"
End Sub

Private Sub IBase_gogo()
    Debug.Print "B: super.gogo()"
End Sub

让我们创建一个实现抽象类'B'的类'A'

'
'class module: 'A'
'

'We started implementing the abstract class B
Implements B

'we define a private type 'myType'
Private Type myType

    'variable that references an instance of 'B'
    objB As B

    'variable that references the interface of 'B'
    objIB As IBase

End Type

'VBA version of 'this'
Private this As myType

'
'Every class that implements 'B' (abstract class)
'you must initialize in your constructor some variables
'of instance.
'
Private Sub Class_Initialize()

    With this

        'we create an instance of object B
        Set .objB = New B

        'the variable 'objIB' refers to the IBase interface, implemented by class B
        Set .objIB = .objB

    End With

End Sub


'Visible only for those who reference interface B
Private Property Get B_super() As IBase

    'returns the methods implemented by 'B', through the interface IBase
    Set B_super = this.objIB

End Property

Private Sub B_go()
    Debug.Print "A: go()"
End Sub
'==================================================

'Class 'A' local method
Sub localMethod1()
    Debug.Print "A: Local method 1"
End Sub

最后,让我们创建“main”模块。

Sub testA()

    'reference to class 'A'
    Dim objA As A

    'reference to interface 'B'
    Dim objIA As B

    'we create an instance of 'A'
    Set objA = New A

    'we access the local methods of instance 'A'
    objA.localMethod1

    'we obtain the reference to interface B (abstract class) implemented by 'A'
    Set objIA = objA

    'we access the 'go' method, implemented by interface 'B'
    objIA.go

    'we go to the 'go' method of the super class
    objIA.super.go

    'we access the 'gogo' method of the super class
    objIA.super.gogo

End Sub

输出结果将显示在验证窗口中:

A: Local method 1
A: go()
B: super.go()
B: super.gogo()

enter image description here


这绝对是非常棒的,比其他答案清晰得多。 - 4AM

1
可以使用默认成员属性来模拟继承。方法是在派生类中给一个名为Super的属性,其类型为超类,然后将其设置为默认成员(通过导出和编辑文件以包含“Attribute Item.VB_UserMemId = 0”,重新导入)。这样,您就可以通过一对圆括号(解析为默认成员)访问超类。
博客文章提供了完整的详细信息,但作者(声明,我)使用“Base”而不是“Super”。
希望这个语法对你足够紧凑。
我还指出,这种方法不像C#那样暴露所有基类的内部结构。这意味着我的方法不会受到脆弱的基类问题的困扰。我的方法保留封装性,因此在我看来更好。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接