代入ステートメントによって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
多くの現代言語と同様に、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
@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
それは素晴らしい働きをします、スコット・ホイットロックに感謝します、あなたは天才です
または、一度に1つのメンバーでオブジェクトをコピーする必要がありますか...
残念ながらそうです。
IDispatchインターフェイスを使用して各プロパティの値をコピーするCOMサーバーをC++で作成することは可能です(ただし、技術的には非常に非常に困難です)。しかし、実際にはこれはHigh Templeプログラミングです。それをしなければならなかったとしても、私がかどうかはわかりません。できますが、10日間の作業のようなものを見ているでしょう(そしてCOMがC++でどのように実装されているかを知っているので、ATLフレームワークに何かがあるかどうかを調べる必要もあります助けるためなど)。
私はVb3、4、5、6を10年間(実践、週5日)使用しましたが、MementosやSave&Storeなどのシリアル化パターンを手動で実装する以外にこれを行うための良い方法は見つかりませんでした。各メンバーを一度に1つずつコピーするための凝った方法に至るまで。