【问题标题】:VBA inheritance, analog of superVBA继承,super的类比
【发布时间】:2011-04-09 19:34:45
【问题描述】:

例如,我有一个实现类 B 的类 A

---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

补充说:不可能跨类的层次共享变量。您应该实现属性(与函数相同)。

【问题讨论】:

    标签: vba excel inheritance


    【解决方案1】:

    在 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

    MS描述的方式是:

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

    这意味着实现继承需要大量显式委托方法。甚至还有一章的副标题:“这不会变得乏味吗?”。 VBA 中的 OOP 是 PITA (TM) 的另一个原因...

    不适合评论的编辑:

    回答你在评论中提出的问题,嗯,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 类型的对象(!);强制委派。
    • @Nikita,我会通读《程序员指南》中涉及“使用对象编程”的其他章节。至于另一个问题,我将编辑我的答案,因为它可能不适合评论。所以几分钟后看看那里......
    【解决方案2】:

    这是我用了很久的方式,通过接口模拟一个抽象类。

    '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
    

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

    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()
    

    【讨论】:

    • 这绝对是伟大的,比其他答案更清晰。
    【解决方案3】:

    人们可以利用一个技巧来模仿继承。它通过使用默认成员属性来工作。

    如果你给你的派生类一个名为 Super 的属性,它的类型是超类,然后将其设为默认成员(通过导出和编辑文件以包含 Attribute Item.VB_UserMemId = 0,重新导入)然后你可以通过一对来访问超类圆括号(解析为默认成员)。

    这个blog post 提供了完整的细节,但作者(披露,我)在那里使用'Base'而不是'Super'

    希望语法对您来说足够紧凑。

    我还指出,这不会像 C# 那样暴露所有基类的内部内容。这意味着我的方法不会遇到脆弱的基类问题。 IE。我的方法保留了封装,使其更好恕我直言。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-10-03
      • 1970-01-01
      • 2016-03-12
      • 2022-11-18
      • 2016-02-11
      • 2022-12-18
      • 1970-01-01
      相关资源
      最近更新 更多