Есть ли способ написать тест на равенство для класса VBA с закрытыми членами, не раскрывая знания о существовании этих закрытых членов? - PullRequest
5 голосов
/ 20 декабря 2010

Я занимаюсь программированием в Excel VBA, но не во многом оно ориентировано на объект.Вот кое-что, что возникает время от времени, что меня беспокоит, и мне интересно, есть ли что-то, что я пропускаю.

В VBA, скажем, у меня есть класс C, определенный с некоторыми закрытыми членами, например:

'...

Private hidden1_ As Double
Private hidden2_ As Double

'...

Если VBA работает как C ++ или (большинство?) Других языков, которые поддерживают ООП, я мог бынапишите функцию-член для выполнения теста на равенство между экземплярами класса 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 с закрытыми членами?»когда Дик ответил на это.

Ответы [ 2 ]

4 голосов
/ 20 декабря 2010

Я бы написал такой класс

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 внутри класса.

1 голос
/ 24 декабря 2010

После повторного изучения у меня есть ответ, но он не совсем удовлетворителен.Как и в большинстве ООП в VBA, это предполагает использование соответствующего интерфейса, но тот факт, что каждый класс (и каждый интерфейс) должен идти в отдельном модуле класса, делает его довольно неуклюжим способом выполнения действий.Итак, вот что:

Скажем, у меня есть класс с именем MyClass (который я называл «C» выше, но сейчас я вызываю «MyClass», чтобы сделать это более понятным).

do будет определять интерфейс, который я на самом деле буду использовать в своем коде, который раскрывает только те вещи о 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 не могут видеть 'init' или 'equalDef'методы MyClass.Они могут видеть только методы «calcSomething» и «равные», которые являются частью интерфейса.

Итак, вопрос официально, но неудовлетворительно ответил, я полагаю.По крайней мере, это дает мне возможность повторить: «ООП в VBA - это PITA (TM)» ...

Вот несколько связанных ответов на вопросы stackoverflow:

Наследование VBA, аналогsuper

Есть ли способ перегрузить процедуру конструктора / инициализации для класса в VBA?

...