【问题标题】:VBA: is there something like Abstract Class?VBA:有像抽象类这样的东西吗?
【发布时间】:2014-02-08 19:33:45
【问题描述】:

我正在使用一个接口来确保一些类似的类实现一些强制方法(子/函数)。

例子:

  • 接口 I1 声明 M1 和 M2 方法
  • C1 和 C2 实现 I1,并有自己的 M1 和 M2 版本。

C1 和 C2 也需要完全相同的方法,例如方法 SM1 和 SM2。

为了避免重复 SM1 和 SM2,我想定义一个抽象类 AC:

  • 实现 I1
  • 定义 SM1 和 SM2。

将由 C1 和 C2 扩展

这个解决方案在 Java 中确实是可能的,但我没有找到在 VBA 中做同样事情的任何文档。 (VB.Net 似乎允许抽象类使用关键字 MustInherit。)

在 VBA 中是否可以确认?

【问题讨论】:

    标签: vba excel interface abstract-class


    【解决方案1】:

    VBA 中没有继承。

    您可以定义一个接口,并使用Implements 关键字在类中实现它。但是,如果您希望基类预先实现共享功能,则必须使用复制粘贴方法。

    相关阅读:
    How to use the Implements in Excel VBA
    How to use comparison methods between class object modules in VBA in a similar manner as VB.NET?

    【讨论】:

    • 好的,没有继承,因此没有从抽象类继承。谢谢。
    【解决方案2】:

    您可以在 VBA 中实现半装饰器 :-) 模式。假设我们有一个基类和两个子类。如果在子类中使用 Implements 关键字,您将确保子类具有与基类相同的接口,同时在每个子类中声明基类的私有实例,并将子类的调用重定向到基类。

    注意:这里的基类是普通类,你仍然可以创建它的实例(所以它不是真正的抽象类)。

    例子:

    ' Standard module
    
    Sub main()
        Dim a As New ChildA
        Dim b As New ChildB
    
        a.State = 2
        b.State = 5
    
        Debug.Print TypeOf a Is Base
        Debug.Print TypeOf b Is Base
    
        TestPolymorphic a
        TestPolymorphic b
    End Sub
    
    Private Sub TestPolymorphic(ByRef obj As Base)
        obj.Polymorphic
    End Sub
    
    ' -----------------------------------------------
    
    ' Base class module
    
    Private m_state As Byte
    
    Public Event StateChanged(oldState As Byte, newState As Byte)
    
    Public Property Get State() As Byte
        State = m_state
    End Property
    
    Public Property Let State(ByVal newState As Byte)
        Dim oldState As Byte
        oldState = m_state
        m_state = newState
        RaiseEvent StateChanged(oldState, newState)
    End Property
    
    Sub Polymorphic()
        Err.Raise 123, , "Implement in child class"
    End Sub
    
    Private Sub Class_Initialize()
        m_state = 1
    End Sub
    
    ' -----------------------------------------------
    
    ' ChildA class module
    
    Implements Base
    Private WithEvents m_base As Base
    
    Private Sub Class_Initialize()
        Set m_base = New Base
    End Sub
    
    Public Property Get State() As Byte
        State = Base_State
    End Property
    
    Public Property Let State(ByVal newState As Byte)
        Base_State = newState
    End Property
    
    Public Sub Polymorphic()
        Base_Polymorphic
    End Sub
    
    Private Property Get Base_State() As Byte
        Base_State = m_base.State
    End Property
    
    Private Property Let Base_State(ByVal newState As Byte)
        m_base.State = newState
    End Property
    
    Private Sub Base_Polymorphic()
        Debug.Print "In Child A ..."
    End Sub
    
    Private Sub m_base_StateChanged(oldState As Byte, newState As Byte)
        Debug.Print "State of 'Child A' instance has changed from " & oldState & " to " & newState
    End Sub
    
    Output:
    ' State of 'Child A' instance has changed from 1 to 2
    ' State of 'Child B' instance has changed from 1 to 5
    ' True
    ' True
    ' In Child A ...
    ' In Child B ...
    

    【讨论】:

      【解决方案3】:

      我对 vba 中抽象类的解决方案: View

      '------------------------- 
      ' Standard module
      
      Sub Main()
      
          Dim objC1 As C1
          Dim objC2 As C2
          Dim objCollection As New Collection
      
          Set objC1 = New C1
          Set objC2 = New C2
      
          With objC1
              .getInterface.M1 "Hello C1!"
              temp1 = .getInterface.M2(objCollection)
      
              .getSuperClass.SM1 "Hi C1!!!"
              temp3 = .getSuperClass.SM2(objCollection)
      
          End With
      
          Debug.Print vbCrLf
      
          With objC2
              .getInterface.M1 "Hello C2!"
              temp1 = .getInterface.M2(objCollection)
      
              .getSuperClass.SM1 "Hi C2!!!"
              temp3 = .getSuperClass.SM2(objCollection)
      
          End With
      
      End Sub
      
      
      ' -----------------------------------------------
      
      ' IAbstracat class module
      
      Sub SM1(strString As String): End Sub
      Function SM2(varItem As Variant) As String: End Function
      
      
      ' -----------------------------------------------
      
      ' Abstracat class module
      
      Implements IAbstract
      
      'Each class must implement these methods, in a particular way
      Sub M1(strString As String): End Sub
      Function M2(varItem As Variant) As String: End Function
      
      
      'The sub classes will extend SM1 and SM2
      Private Sub IAbstract_SM1(strString As String)
          Debug.Print "Sub IAbstract_SM1: " & strString
      End Sub
      
      
      'The sub classes will extend SM1 and SM2
       Private Function IAbstract_SM2(varItem As Variant) As String
      
          Dim strMyString As String
      
          strMyString = "Function IAbstract_SM2 => ObjPtr(varItem): " & ObjPtr(varItem)
          Debug.Print strMyString
      
          IAbstract_SM2 = strMyString
      
      End Function
      
      
      ' -----------------------------------------------
      
      ' C1 class module
      
      Implements Abstract
      
      Private Type TC1
          objConcretSuperClass As Abstract
          objInterfaceSuperClass As IAbstract
          objInterfaceSubClass As Abstract
      End Type
      
      Private this As TC1
      
      
      'if you do not need to initialize anything, then this is it:
      Private Sub Class_Initialize()
      
          With this
      
              'creating an instance of class' Abstract'
              Set .objConcretSuperClass = New Abstract
      
      
              'Referencing the' Abstract 'interface, where are the extended methods
              Set .objInterfaceSuperClass = .objConcretSuperClass
      
      
              'Creating a refence for the C1 interface, which is the class' Abstract'
              'Here we have the particular implementations of M1 and M2
              Set .objInterfaceSubClass = Me
      
          End With
      
      End Sub
      
      
      
      'With this we can do:
      '   set objC1 = New C1
      '   objC1.getInterface.Abstract_M1
      '   objC1.getInterface.Abstract_M2
      Property Get getInterface() As Abstract
          Set getInterface = this.objInterfaceSubClass
      End Property
      
      
      
      'With this we can call the methods defined in' Abstract ': SM1 and SM2
      '   set objC1 = New C1
      '   objC1.getSuperClass.SM1 "hello!"
      '   temp = objC1.getSuperClass.SM2 (New Collection)
      Property Get getSuperClass() As IAbstract
          Set getSuperClass = this.objInterfaceSuperClass
      End Property
      
      'Here we have the particular implementations of M1 and M2
      Private Sub Abstract_M1(strString As String)
          Debug.Print "Class C1 => Sub Abstract_M1: " & strString
      End Sub
      
      Private Function Abstract_M2(varItem As Variant) As String
          Debug.Print "Class C1 => Function Abstract_M2: " & ObjPtr(varItem)
      End Function
      
      
      ' -----------------------------------------------
      
      ' C2 class module
      
      Implements Abstract
      
      Private Type TC2
          objConcretSuperClass As Abstract
          objInterfaceSuperClass As IAbstract
          objInterfaceSubClass As Abstract
      End Type
      
      Private this As TC2
      
      'if you do not need to initialize anything, then this is it:
      Private Sub Class_Initialize()
      
          With this
      
              'creating an instance of class' Abstract'
              Set .objConcretSuperClass = New Abstract
      
              'Referencing the' Abstract 'interface, where are the extended methods
              Set .objInterfaceSuperClass = .objConcretSuperClass
      
              'Creating a refence for the C1 interface, which is the class' Abstract'
              'Here we have the particular implementations of M1 and M2
              Set .objInterfaceSubClass = Me
      
          End With
      
      End Sub
      
      
      
      'With this we can do:
      '   set objC2 = New C2
      '   objC2.getInterface.Abstract_M1
      '   objC2.getInterface.Abstract_M2
      Property Get getInterface() As Abstract
          Set getInterface = this.objInterfaceSubClass
      End Property
      
      'With this we can call the methods defined in' Abstract ': SM1 and SM2
      '   set objC1 = New C1
      '   objC1.getSuperClass.SM1 "hello!"
      '   temp = objC1.getSuperClass.SM2 (New Collection)
      Property Get getSuperClass() As IAbstract
          Set getSuperClass = this.objInterfaceSuperClass
      End Property
      
      'Here we have the particular implementations of M1 and M2
      Private Sub Abstract_M1(strString As String)
          Debug.Print "Class C2 => Sub Abstract_M1: " & strString
      End Sub
      
      Private Function Abstract_M2(varItem As Variant) As String
          Debug.Print "Class C2 => Function Abstract_M2: " & ObjPtr(varItem)
      End Function
      

      立即检查窗口(CTRL + G):

      Class C1 => Sub Abstract_M1: Hello C1!
      Class C1 => Function Abstract_M2: 550324728
      Sub IAbstract_SM1: Hi C1!!!
      Function IAbstract_SM2 => ObjPtr(varItem): 550324728
      
      Class C2 => Sub Abstract_M1: Hello C2!
      Class C2 => Function Abstract_M2: 550324728
      Sub IAbstract_SM1: Hi C2!!!
      Function IAbstract_SM2 => ObjPtr(varItem): 550324728
      

      【讨论】:

        猜你喜欢
        • 2013-05-02
        • 1970-01-01
        • 1970-01-01
        • 2011-01-24
        • 2013-07-30
        • 2014-09-29
        • 1970-01-01
        • 1970-01-01
        • 2023-03-05
        相关资源
        最近更新 更多