6

私はかなりの量のExcelVBAプログラミングを行っていますが、オブジェクト指向のプログラミングはそれほど多くありません。これが時々出てくるもので、私を悩ませています。私が見逃しているものがあるのではないかと思います。

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ではコンパイルされません。この種のことを行うために私がこれまでに思いついた最善の方法は、代わりに次のような2つのメンバー関数を定義することです。

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)です」を繰り返す機会があります...

関連するスタックオーバーフローの回答は次のとおりです。

VBA継承、スーパーのアナログ

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 に答える