Ein Pointer/Zeiger ist ein Verweis irgendwo hin. Er kann nur auf schon existierende Objekte zeigen. Instanz ist hier lediglich ein anderes Wort für Objekt.
Man kann Objekte/Instanzen entweder lokal erzeugen (das landet dann auf dem Stack) oder eben dynamisch (das landet dann auf dem Heap). Nehmen wir an es gäbe die Klasse Foo.
Statische Instanzierung sieht so aus:
|
C-/C++-Quelltext
|
1
2
3
|
{
Foo objekt; // hier wird lokal ein Objekt angelegt.
}
|
Um nochmal zu verdeutlich, was ein Zeiger ist:
|
C-/C++-Quelltext
|
1
2
3
4
5
6
7
8
9
10
11
12
|
{
Foo objekt1;
Foo objekt2;
Foo * verweis = &objekt1; // "verweis" zeigt nun auf objekt1.
verweis->irgendwas(); // irgendas wird auf objekt1 aufgerufen
verweis = objekt2;
verweis->irgendwas(); // irgendas wird jetzt auf objekt2 aufgerufen
}
|
Man kann Objekte auch dynamisch anlegen:
|
C-/C++-Quelltext
|
1
2
3
4
|
{
Foo * verweis = new Foo(); // hier wird dynamisch ein Objekt angelegt.
...
}
|
new Foo() legt irgendwo ein Objekt an, also eine Instanz des Typs Foo. Das Objekt ist im Grunde nicht anders, als die Objekte, die wir oben angelegt haben. Es hat nur keinen direkten Namen, unter dem wir es ansprechen können. Wir haben "nur" einen Zeiger darauf. Geht uns das Objekt verloren, z.B. wen wir "verweis" einfach auf was anderes Zeigen lassen. Das Objekt ansich existiert noch irgendwo, aber wir kämen nciht mehr dran.
Außerdem müssen wir dynamisch angelegte Objekte selbst auch wieder beseitigen, indem wir delete verwenden.
-------
Nun kann ich folgendes machen: Ich baue eine Funktion, die ein Objekt anlegt, und gebe dann einen Verweis auf dieses Objekt zurück:
|
C-/C++-Quelltext
|
1
2
3
4
5
|
Foo * erzeugeEinFoo ()
{
Foo * temp = new Foo();
return temp;
}
|
Geht natürlich kürzer. der Zeiger "temp" ist im Grunde überflüssig. Wir wollen ja einfach nur das von new erzeugte Objekt zurückgeben. Aber vielen fällt es einfacher das ganze zu verstehen, wenn man auch die gerae gezeigte längere Version einmal vorführt.
|
C-/C++-Quelltext
|
1
2
3
4
|
Foo * erzeugeEinFoo ()
{
return new Foo();
}
|
So. Anwenden können wir das ganze jetzt so:
|
C-/C++-Quelltext
|
1
2
3
4
|
{
Foo * verweis = erzeugeEinFoo();
...
}
|
"erzeugeEinFoo" erzeugt jetzt ein Foo-Objekt und wir bekommen einen Zeiger darauf, den wir in "verweis" speichern. Dann können wir wie gewohnt mit dem Objekt arbeiten.
Warum machen wir das ganze. Warum erzeugen wir dynamisch ein Objekt in "erzeugeEinFoo"? Warum geben wir nicht direkt ein Objekt wieder, sondern nur einen Verweis?
Tja, einfach mal durchspielen:
|
C-/C++-Quelltext
|
1
2
3
4
5
|
Foo erzeugeEinFoo2 ()
{
Foo temp;
return temp;
}
|
Und in kurz:
|
C-/C++-Quelltext
|
1
2
3
4
|
Foo erzeugeEinFoo2 ()
{
return Foo();
}
|
Vergleichen wir beide Funktionen mal:
|
C-/C++-Quelltext
|
1
2
3
4
5
6
7
8
|
{
Foo objekt; // (1)
Foo *verweis; // (2)
objekt = erzeugeEinFoo2(); // (3)
verweis = erzeugeEinFoo(); // (4)
...
}
|
Bei (1) wird direkt schon ein Objekt angelegt, bei (2) hingegen nicht. Es existiert nur ein nicht initialisierter Zeiger (also einen, den wir noch nciht benutzen können).
Bei (3) Wird nun von erzeugeEinFoo2() ein Objekt erzeugt und dieses wird dann in das bereits vorhandene Objekt namens "objekt" kopiert. Nehmen wir mal an, das es sich bei Foo um eine Klasse handelt, die Bilder speichert, die auch ein paar MB groß sein können, dann könnten hier gerade mal eben ein paar MB kopiert worden sein.
Bei (4) wird einfach "verweis" auf das von "erzeugeEinFoo" erzeugte Objekt gesetzt. Egal, wie groß oder klein das eigentliche Objekt ist, das ganze geht blitz schnell. Das eigentliche Objekt wurde ja gar nciht angefasst.
Natürlich sind meine Beispielfunktionen etwas sinnlos, weil sie einfach new mit einem bestimmte Typen, bzw. einfach nur einen Konstruktoraufruf ersetzen.
Um mal konkreter auf dein Beispiel einzugehen:
|
C-/C++-Quelltext
|
1
|
BITMAP *irgendeinBild = LoadBitmap (...);
|
LoadBitmap erzeugt ein Objekt. Dieses Objekt speichert jetzt ein Bitmap. Das Objekt ist jetzt also schon erzeugt und vermutlich recht groß (wie es bei Bitmaps nunmal so ist). Wozu sollten wir jetzt selbst nochmal ein Objet erzeugen und das bereits erzeugte Bitmap da reinkopieren? Das wäre ja unnötiger Aufwand. Außerdem hätten wir zweimal die selben Daten gespeichert. Wäre natürlich Quatsch. Also setzten wir einfah einen Zeiger auf das bereits durch LoadBitmap erzeugte Objekt.
Ich hoffe ich konnte einiger Maßen helfen.