Buchempfehlung
Mikrocomputertechnik mit Controllern der Atmel AVR-RISC-Familie
Mikrocomputertechnik mit Controllern der Atmel AVR-RISC-Familie
Umfassend, aber leicht verständlich führt dieses Buch in die Programmierung von ATMEL AVR Mikrocontrollern ein. [Mehr Infos...]
FreeBASIC-Chat
Es sind Benutzer im FreeBASIC-Chat online.
(Stand:  )
FreeBASIC bei Twitter
Twitter FreeBASIC-Nachrichten jetzt auch über Twitter erhalten. Follow us!

Tutorial

Type als Objekt - Das UDT-Tutorial Teil 2

von RedakteurMODSeite 2 von 3

Copy Constructor

Ein Copy Constructor ist ein spezieller Constructor-Typ, der zum Erstellen einer Kopie eines bestehenden Objektes dient. Mit einem Code wie diesem:

Type foo
    '...
End Type

Dim As foo a
Dim As foo b = a

Was passiert ist, dass FreeBASIC automatisch versteckten Code zum Erstellen von b(als Kopie von a) erzeugt. Dies ist der Standard-Copy Constructor, und kopiert einfach nur die Datenfelder (Elemente) rüber. Wir können auch unseren eigenen Copy Constructor definieren. Hier folgt ein kurzer Schnipsel, der zeigt, wie er deklariert wird.

Type foo
  Declare Constructor(ByRef obj As foo)
  '...
End Type

Das Thema vertiefen wir doch gleich mal.

Tiefe/Oberflächliche Kopie

Im vorigen Beispiel haben wir mit dem Code 'Dim As foo b = a', das benutzt, was man Shallow Copy oder eben Oberflächliche Kopie nennt, die Datenfelder werden einfach nur kopiert, manchmal ist die jedoch nicht erwünscht. Was würde passieren, wenn eins der Elemente ein Pointer ist? Nun, die Adresse auf die der Pointer zeigt würde kopiert werden, mit dem Effekt, dass beide Objekte auf exakt denselben Speicherbereich zeigen. Ein Beispiel dafür:

Type foo
  x As Integer Ptr
End Type

Dim As foo a

a.x = Allocate(SizeOf(Integer))
*a.x = 42

Dim As foo b = a

Print *a.x, *b.x

*a.x = 420

Print *a.x, *b.x

DeAllocate(a.x)

Weil beide auf den selben Speicherbereich zeigen, betreffen Änderungen bei einem auch den anderen. Wie schon im vorigen Kapitel beim Copy Constructor erklärt, erzeugt FreeBASIC standardmäßig den Code für oberflächliche Kopien. Das stimmt auch auf Zuweisung zu, wie z.B.:

Dim As foo a, b

b = a

Auch in diesem Fall erzeugt FreeBASIC einen Standard-Zuweisungsoperator (Let) zum Durchführen der Shallow Copy. Um 'Deep Copies', also Tiefe Kopien zu machen, müssen wir einen Copy Constructor definieren und einen Zuweisungsoperator überladen, um unseren Type zu akzeptieren.
Hier ein Verwendungsbeispiel:

Type foo
  Declare Constructor()
  Declare Constructor(ByRef obj As foo)
  Declare Destructor()

  Declare Operator Let(ByRef obj As foo)

  x As Integer Ptr
End Type

Constructor foo()
  Print "Default ctor"
  x = Callocate(SizeOf(Integer))
End Constructor

Constructor foo(ByRef obj As foo)
  Print "Copy ctor"
  x = Callocate(SizeOf(Integer))
  *x = *obj.x
End Constructor

Destructor foo()
  Print "dtor"
  DeAllocate(x)
End Destructor

Operator foo.Let(ByRef obj As foo)
  Print "Let"
  *x = *obj.x
End Operator

Dim As foo a

*a.x = 42

Dim As foo b = a 'Uses the copy constructor

Print *a.x, *b.x

*a.x = 420

Print *a.x, *b.x

Man erkennt, dass der Copy Constructor in der Zeile 'Dim As foo b = a' aufgerufen wird und diesmal reservieren wir etwas Speicher und kopieren die Daten in den neuen Copy Constructor, sodass wir x in einem Objekt ändern können, ohne dies auch im anderen zu tun.
Wenn wir den Haupt-Code wie folgt ändern:

Dim As foo a, b

*a.x = 42
b = a    'Der Zuweisungsoperator (Let) wird diesmal hier benutzt

Print *a.x, *b.x

*a.x = 420

Print *a.x, *b.x

dann wird diesmal der Zuweisungsoperator benutzt. Beachte, dass wir im Zuweisungsoperator-Code keinen Speicher zu reservieren brauchen, da dies schon der Standard-Constructor gemacht hat, wir müssen also nur die Daten kopieren. Die Zeile '*x = *obj.x' führt diese Kopie durch. Wenn wir etwas Komplizierteres hätten, wie ein dynamisches Speicher-Array, dann müssten wir auch den Speicher neu reservieren, damit er die korrekte Größe für die zu kopierenden Daten hat. Hier ist ein fortgeschritteneres Beispiel, um das zu zeigen:

Type foo
  Declare Constructor(ByVal num_elements As Integer)
  Declare Constructor(ByRef obj As foo)
  Declare Destructor()

  Declare Operator Let(ByRef obj As foo)

  x As Integer Ptr
  size As Integer
End Type

Constructor foo(ByVal num_elements As Integer)
  Print "Default ctor"
  x = Callocate(SizeOf(Integer) * num_elements)
  size = num_elements
End Constructor

Constructor foo(ByRef obj As foo)
  Print "Copy ctor"
  x = Callocate(SizeOf(Integer) * obj.size)
  size = obj.size
  For i As Integer = 0 To size - 1
    x[i] = obj.x[i]
  Next i
End Constructor

Destructor foo()
  Print "dtor"
  DeAllocate(x)
End Destructor

Operator foo.Let(ByRef obj As foo)
  Print "Let"
  x = ReAllocate(x, SizeOf(Integer) * obj.size)
  size = obj.size
  For i As Integer = 0 To size - 1
    x[i] = obj.x[i]
  Next i
End Operator

Dim As foo a = foo(5)

a.x[0] = 42
a.x[1] = 420

Dim As foo b = a 'benutzt den Copy Constructor

Print a.x[0], a.x[1], b.x[0], b.x[1]

b.x[0] = 10
b.x[1] = 20

Print a.x[0], a.x[1], b.x[0], b.x[1]

b = a 'benutzt jetzt den Zuweisungsoperator

Print a.x[0], a.x[1], b.x[0], b.x[1]

Das mag auf den ersten Blick sehr komplex erscheinen, aber es ist es wert, nochmal gelesen zu werden und mit den Beispielen zu experimentieren. Es ist nicht mehr sehr geheimnisvoll, wenn man sich dran gewöhnt hat.

 

Gehe zu Seite Gehe zu Seite  1  2  3  
Zusätzliche Informationen und Funktionen
  • Das Tutorial wurde am 06.09.2010 von RedakteurMOD angelegt.
  • Die aktuellste Version wurde am 28.08.2011 von RedakteurMOD gespeichert.
  Bearbeiten Bearbeiten  

  Versionen Versionen