6

我做了相当多的 Excel VBA 编程,但不是很多都是面向对象的。这是不时出现的东西,这让我很烦恼,我想知道我是否缺少一些东西。

在 VBA 中,假设我有一个 C 类,其中定义了一些私有成员,如下所示:

'...

Private hidden1_ As Double
Private hidden2_ As Double

'...

如果 VBA 像 C++ 或(大多数?)其他支持 OOP 的语言一样工作,我可以编写一个成员函数来在 C 类的实例之间进行相等性测试,如下所示:

'Error: won't compile!
Public Function equal(cinst As C) As Boolean
    equal = (hidden1_ = cinst.hidden1_ And hidden2_ = cinst.hidden2_)
End Function

当然,这不会在 VBA 中编译,因为类成员函数只能访问调用它们的同一实例的私有类成员。我做过的最好的事情就是定义两个成员函数,如下所示:

Public Function equalDef(hidden1 As Double, hidden2 As Double) As Boolean
    equalDef = (hidden1_ = hidden1 And hidden2_ = hidden2)
End Function

Public Function equal(cinst As C) As Boolean
    equal = cinst.equalDef(hidden1_, hidden2_)
End Function

它很麻烦,并且暴露了私有类成员存在的知识,但至少它避免了实际暴露私有类成员的

这是我能做的最好的吗?

编辑:

像往常一样,在回答之后,我意识到了一种更好的方式来表达这个问题。它的标题是“是否有一种更简洁的方法可以为具有私有成员的 VBA 类编写相等测试?” 当迪克回答时。

4

3 回答 3

4

我会这样写课程

Private mdhidden1_ As Double
Private mdhidden2_ As Double

Public Property Get hidden1_() As Double

    hidden1_ = mdhidden1_

End Property

Public Property Get hidden2_() As Double

    hidden2_ = mdhidden2_

End Property

Private Sub Class_Initialize()

    'some method of setting variables private to the class
    mdhidden1_ = 1
    mdhidden2_ = 2

End Sub

Public Property Get IsEquivalent(clsCompare As C) As Boolean

    IsEquivalent = Me.hidden1_ = clsCompare.hidden1_ And Me.hidden2_ = clsCompare.hidden2_

End Property

如果您无论如何都被迫公开该成员的知识,则不妨将其设为只读属性(Get,但不能 Let)。然后你可以在类中创建 IsEquivalent 布尔属性。

于 2010-12-20T15:45:03.190 回答
1

再次调查后,我有了答案,但并不完全令人满意。与 VBA 中的大多数 OOP 一样,它涉及使用适当的接口,但是每个类(和每个接口)都必须放在单独的类模块中,这使得它成为一种非常笨拙的做事方式。所以这里是:

假设我有一个名为 MyClass 的类(我在上面称它为“C”,但我现在称它为“MyClass”以使这一点更清楚。)

要做的事情是定义一个我会在我的代码中实际使用的接口,它只公开我想要真正公开的关于 MyClass 的东西。假设这段代码在一个名为 IMyClass 的类模块中:

Public Function calcSomething()

End Function

Public Function equal(cinst As IMyClass) As Boolean

End Function

然后我有一个名为 MyClass 的类,在类模块中使用以下代码定义:

Implements IMyClass

Private hidden1_ As Double
Private hidden2_ As Double

Public Sub init(h1 As Double, h2 As Double)
    hidden1_ = h1
    hidden2_ = h2
End Sub

Public Function equalDef(hidden1 As Double, hidden2 As Double) As Boolean
    equalDef = (hidden1_ = hidden1 And hidden2_ = hidden2)
End Function

Private Function IMyClass_calcSomething() As Variant
    IMyClass_calcSomething = hidden1_ * hidden2_
End Function

Private Function IMyClass_equal(cinst As IMyClass) As Boolean
    If TypeOf cinst Is MyClass Then
        Dim asMyClass As MyClass
        Set asMyClass = cinst

        IMyClass_equal = asMyClass.equalDef(hidden1_, hidden2_)
    End If
End Function

下面是一些可以放在常规模块中的代码:

Public Function mkMyClass(h1 As Double, h2 As Double) As IMyClass
    Dim ret As MyClass
    Set ret = New MyClass

    Call ret.init(h1, h2)

    Set mkMyClass = ret
End Function

Public Sub useMyClass()
    Dim mc1 As IMyClass
    Set mc1 = mkMyClass(42, 99)

    Dim mc2 As IMyClass
    Set mc2 = mkMyClass(42, 99)

    Dim mc3 As IMyClass
    Set mc3 = mkMyClass(99, 42)

    Debug.Print mc1.calcSomething
    Debug.Print mc1.equal(mc2)

    Debug.Print mc3.calcSomething
    Debug.Print mc3.equal(mc2)
End Sub

在 'useMyClass' 例程中,您可以验证各种 mc1、mc2 和 mc3 变量看不到 MyClass 的 'init' 或 'equalDef' 方法。他们只能看到作为接口一部分的“calcSomething”和“equal”方法。

所以,我猜,这个问题正式但不令人满意地回答了。至少它让我有机会重复“VBA 中的 OOP 是 PITA (TM)”......

以下是一些相关的stackoverflow答案:

VBA继承,super的类比

有没有办法重载VBA中类的构造函数/初始化过程?

于 2010-12-24T07:13:33.650 回答
1

我知道这是一个旧帖子,但我仍然想回答。以下代码不向用户公开任何私有变量,并且仍然允许在对象之间进行比较:

'MyClass
Private m_data As Double
Private Const epsilon As Double = 0.00001


Public Function IsEqual(ByRef cls As MyClass) As Boolean
    IsEqual = cls.Comparator(m_data)
End Function

Public Function Comparator(ByVal d As Double) As Boolean
    Comparator = Abs((d - m_data)) < epsilon
End Function

Property Get MyString() As String
    MyString = Chr((CLng(m_data) Mod 26) + 65) & Chr((CLng(m_data * 100) Mod 26) + 65)
End Property

Property Let MyString(s As String)
    If Len(s) = 0 Then
        m_data = epsilon / 10
        Exit Property
    End If
    m_data = Len(s) / (Len(s) - Len(Replace(s, " ", "")))
End Property

'Module
Public Sub mySub2()
Dim s As String
Dim obj1 As MyClass
Dim obj2 As MyClass

    Set obj1 = New MyClass
    Set obj2 = New MyClass

    s = InputBox("Enter a sentence:")
    Debug.Print s

    obj1.MyString = s
    obj2.MyString = ""

    Debug.Print "Does Obj1(" & obj1.MyString & ") = Obj2(" & obj2.MyString & ")?  " & obj1.IsEqual(obj2)

    obj2.MyString = s

    Debug.Print "Does Obj1(" & obj1.MyString & ") = Obj2(" & obj2.MyString & ")?  " & obj1.IsEqual(obj2)

End Sub

使用以下输出:

The quick brown fox jumps over the lazy moon
Does Obj1(GE) = Obj2(AA)?  False
Does Obj1(GE) = Obj2(GE)?  True
于 2020-02-25T21:32:36.717 回答