有没有办法为私有成员编写VBA类的相等测试而不暴露这些私有成员存在的知识?

jto*_*lle 5 oop vba encapsulation private-members

我做了大量的Excel VBA编程,但不是很多面向对象的.这是偶然出现的东西,这让我感到困扰,我想知道是否有一些我缺少的东西.

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

'...

Private hidden1_ As Double
Private hidden2_ As Double

'...
Run Code Online (Sandbox Code Playgroud)

如果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
Run Code Online (Sandbox Code Playgroud)

当然,这不会在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
Run Code Online (Sandbox Code Playgroud)

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

这是我能做的最好的吗?

编辑:

像往常一样,在回答之后,我意识到了一个更好的方式来表达这个问题.它的标题是"有没有更简洁的方法为私人成员的VBA类写一个平等测试?" 当迪克回答时.

jto*_*lle 1

再次研究这个问题后,我有了答案,但并不完全令人满意。与 VBA 中的大多数 OOP 一样,它涉及使用适当的接口,但每个类(以及每个接口)都必须位于单独的类模块中,这一事实使其成为一种相当笨拙的执行方式。所以这里是:

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

要做的事情是定义一个我将在代码中实际使用的接口,该接口仅公开我想要真正公开的有关 MyClass 的内容。假设此代码位于名为 IMyClass 的类模块中:

Public Function calcSomething()

End Function

Public Function equal(cinst As IMyClass) As Boolean

End Function
Run Code Online (Sandbox Code Playgroud)

然后我有一个名为 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
Run Code Online (Sandbox Code Playgroud)

以下是常规模块中的一些代码:

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
Run Code Online (Sandbox Code Playgroud)

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

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

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

VBA继承,类比super

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