web-dev-qa-db-ja.com

VB6でのオブジェクトの割り当て

代入ステートメントによってVB6で2つの同一のオブジェクトを作成しようとしています。このようなもの...

Dim myobj1 As Class1
Dim myobj2 As Class1

Set myobj1 = New Class1
myobj1.myval = 1
Set myobj2 = myobj1

これにより、2つのオブジェクトが作成されるのではなく、同じオブジェクトへの2つの参照が作成されることが明らかになりました。これは、私が求めているものではありません。この種の方法で2番目のオブジェクトを作成する方法はありますか、それとも一度に1つのメンバーでオブジェクトをコピーする必要がありますか...

Set myobj2 = new Class1
myobj2.mem1 = myobj1.mem1
...

編集2 Scott Whitlockが彼の優れた回答を更新し、私は彼の変更をこの現在機能しているコードスニペットに組み込みました。

Private Type MyMemento
     Value1 As Integer
     Value2 As String
End Type

Private Memento As MyMemento

Public Property Let myval(ByVal newval As Integer)
Memento.Value1 = newval
End Property

Public Property Get myval() As Integer
myval = Memento.Value1
End Property

Friend Property Let SetMemento(new_memento As MyMemento)
    Memento = new_memento
End Property

Public Function Copy() As Class1
     Dim Result As Class1
     Set Result = New Class1
     Result.SetMemento = Memento
     Set Copy = Result
End Function

次に、コードで割り当てを実行します。

Set mysecondobj = myfirstobj.Copy
26
Brian Hooper

多くの現代言語と同様に、VB6には値型と参照型があります。クラスは参照型を定義します。一方、Integerのような基本的な型は値型です。

基本的な違いは割り当てにあります。

_Dim a as Integer
Dim b as Integer
a = 2
b = a
a = 1
_

その結果、aは1、bは2になります。これは、値型の割り当てによってコピーが作成されるためです。これは、各変数にスタック上のvalueに割り当てられたスペースがあるためです(VB6の場合、整数はスタック上で2バイトを占めます)。

クラスの場合、動作は異なります。

_Dim a as MyClass
Dim b as MyClass
Set a = New MyClass
a.Value1 = 2
Set b = a
a.Value1 = 1
_

その結果、_a.Value1_と_b.Value1_の両方が1になります。これは、オブジェクトの状態がスタックではなくヒープに格納されているためです。オブジェクトへの参照のみがスタックに格納されるため、_Set b = a_は参照を上書きします。興味深いことに、VB6は、Setキーワードの使用を強制することにより、これについて明示的にしています。他のほとんどの現代言語はこれを必要としません。

これで、独自の値型を作成できます(VB6では、ユーザー定義型と呼ばれますが、他のほとんどの言語では、構造体または構造体と呼ばれます)。これが チュートリアル です。

クラスとユーザー定義型(参照型であるクラスと値型であるUDTを除く)の違いは、クラスにはUDTでは不可能な動作(メソッドとプロパティ)を含めることができるということです。レコードタイプのクラスを探しているだけの場合は、UDTが解決策になる可能性があります。

これらの手法を組み合わせて使用​​できます。データと一緒に含めたい特定の動作と計算があるため、クラスが必要だとします。 memento pattern を使用して、UDT内のオブジェクトの状態を保持できます。

_Type MyMemento
    Value1 As Integer
    Value2 As String
End Type
_

クラスでは、all内部状態がタイプMyMementoのプライベートメンバー内に格納されていることを確認してください。プロパティとメソッドを記述して、その1つのプライベートメンバー変数のデータのみを使用するようにします。

これで、オブジェクトのコピーを作成するのは簡単です。クラスの新しいインスタンスを返すCopy()という名前の新しいメソッドをクラスに記述し、それを独自のメモリのコピーで初期化します。

_Private Memento As MyMemento

Friend Sub SetMemento(NewMemento As MyMemento)
    Memento = NewMemento
End Sub

Public Function Copy() as MyClass
    Dim Result as MyClass
    Set Result = new MyClass
    Call Result.SetMemento(Memento)
    Set Copy = Result
End Function
_

Friendはプロジェクト外のものからのみ非表示にするため、SetMementoサブを非表示にすることはあまりありませんが、VB6でできることはそれだけです。

HTH

38
Scott Whitlock

@Scott Whitlock、私はあなたのコードを機能させることができませんでしたが、それが機能するならそれは素晴らしいことです。

私はメメントタイプを置く通常のモジュールを作成しました

Type MyMemento
    Value1 As Integer
    Value2 As String
End Type

次に、コードを使用してMyClassというクラスモジュールを作成します

Private Memento As MyMemento

Friend Sub SetMemento(NewMemento As MyMemento)
        Memento = NewMemento
End Sub

Public Function Copy() as MyClass
    Dim Result as MyClass
    Set Result = new MyClass
    Result.SetMemento(Memento)
    Set Copy = Result
End Function

最後に、このような別の通常のモジュールでコピー関数を呼び出そうとします

Sub Pruebas()
    Dim Primero As MyClass, segundo As MyClass
    Set Primero = New MyClass
    Set segundo = New MyClass
    Set segundo = Primero.Copy
End Sub

メッセージが表示されます(写真の下):エラーデコンプリケーション:El tipo de agumento deByRef一致しません

これが画像です(10ポイントに満たないのでここにリンクがあります): http://i.stack.imgur.com/KPdBR.gif

私は英語でメッセージを受け取ることができませんでした、私はスペインに住んでいます。

VBA Excelで例を提供していただけませんか?、私は本当にこれを機能させようとしています。

あなたの仕事をありがとう

===============================================

編集:解決された問題:

問題はオンラインの「Result.SetMemento(Memento)」にあり、VBAでは「Call」で呼び出す必要がありました

Public Function Copy() As MyClass
    Dim Result As MyClass
    Set Result = New MyClass
    Call Result.SetMemento(Memento)
    Set Copy = Result
End Function

それは素晴らしい働きをします、スコット・ホイットロックに感謝します、あなたは天才です

3
verzulsan

または、一度に1つのメンバーでオブジェクトをコピーする必要がありますか...

残念ながらそうです。

IDispatchインターフェイスを使用して各プロパティの値をコピーするCOMサーバーをC++で作成することは可能です(ただし、技術的には非常に非常に困難です)。しかし、実際にはこれはHigh Templeプログラミングです。それをしなければならなかったとしても、私がかどうかはわかりません。できますが、10日間の作業のようなものを見ているでしょう(そしてCOMがC++でどのように実装されているかを知っているので、ATLフレームワークに何かがあるかどうかを調べる必要もあります助けるためなど)。

私はVb3、4、5、6を10年間(実践、週5日)使用しましたが、MementosやSave&Storeなどのシリアル化パターンを手動で実装する以外にこれを行うための良い方法は見つかりませんでした。各メンバーを一度に1つずつコピーするための凝った方法に至るまで。

2
Binary Worrier