Erfahrene
C-Programmierer sind immer wieder verwundert, dass Zeigertypen in C++ nicht
implizit ineinander konvertiert werden können. Zeiger unterschiedlicher Typen
wie z.B. pa
und pb
mit den Definitionen
struct A { ...
}; //
Klasse A
struct B { ...
}; //
Klasse B
A* pa = 0;
B* pb = 0;
können in C, nicht aber in C++ beliebig zugewiesen werden. Die Anweisung
pa = pb; //
OK in C, nicht jedoch in C++
ist in C++ syntaktisch falsch. Eine Ausnahme bildet lediglich der
allgemeine Zeigertyp void*.
Jeder Zeigertyp kann implizit zu void*
gewandelt werden, nicht jedoch umgekehrt. Die Anweisung
void*
pv = pa; // OK
ist daher syntaktisch korrekt, nicht erlaubt ist dagegen
pa = pv; //
Fehler!
Wäre dies erlaubt, müsste syntaktisch
genauso
pb = pv; //
Fehler!
erlaubt sein – da pv
ein untypisierter Zeiger ist, weiß der Compiler nicht, ob pv gerade auf ein A, ein B- oder auf
ein Objekt eines ganz anderen Typs zeigt. Die Wandlung wird daher aus
Sicherheitsgründen abgelehnt. Dies ist eine Sicherheitsmaßnahme, die der
Programmierer allerdings durch Angabe einer expliziten
Typwandlung (s.u.) außer Kraft setzen kann.
Zeigertypen können nicht implizit in numerische Typen gewandelt
werden, die umgekehrte Wandlung ist ebenfalls nicht implizit möglich. Selbst
wenn Zeigertypen („Adressen“) und ein integraler Typ (meist int) die gleiche Größe haben
sollten (was auf den meisten modernen Maschinen wohl der Fall sein dürfte),
sind Anweisungen wie
int i = pa; // Fehler
pa = i;
// Fehler
nicht möglich.
Eine Sonderstellung nimmt allerdings die numerische Konstante 0 ein. Sie
ist kompatibel mit jedem Zeigertyp in dem Sinne, dass für jeden Typ T eine
implizite Wandlung in den Nullzeiger des Typs T erfolgen kann. Man kann also
z.B. Anweisungen wie
T* t = 0; // OK
...
t = 0; //
OK
...
if ( t == 0 ) ... // OK
schreiben. In allen Fällen erfolgt eine implizite (automatische)
Wandlung der Konstanten 0
in einen Zeiger vom Typ T*
mit einem wohldefinierten Wert, den so genannten Nullzeiger vom Typ T. Der Standard schreibt vor, dass der
Nullzeiger unterschiedlich zu jedem Zeiger ist, der von einer erfolgreichen
Objektallokation (mit new
oder malloc)
herrührt. Der Nullzeiger zeigt also niemals auf ein gültiges Objekt.
Beachten Sie
bitte, dass die numerische Konstante 0 und der Nullzeiger für einen Typ T nicht unbedingt
die gleiche Bitrepräsentation im Rechner besitzen müssen – es handelt sich bei
beiden um ganz verschiedene Dinge. Ebenso ist nicht vorgeschrieben, dass die
Nullzeiger unterschiedlicher Typen T1 und T2 auch die gleiche Repräsentation im Speicher
haben müssen.
Für
Referenzen gilt analog das Gleiche wie für Zeiger: Referenzen unterschiedlicher
Typen können nicht implizit ineinander gewandelt werden. Dies funktioniert
schon aus dem Grunde nicht, weil Referenzen keine eigenen Objekte sind.
In den
Anweisungen
void f( A& a_in, B& b_in )
{
b_in =
a_in; // Fehler!
...
}
erhält ja nicht die Referenz b_in einen anderen Wert, sondern es erfolgt
eine Zuweisung des referenzierten Objekts selber. Dies funktioniert nur, wenn
die Typen A
und B zuweisungskompatibel sind – d.h. wenn
auch folgende Anweisungen möglich sind:
A a;
B b;
b = a;
// OK wenn A
zuweisungskompatibel zu B ist
Allerdings lässt sich diese Einschränkung auch bei
Referenzen durch Verwendung einer expliziten Wandlung (s.u.) umgehen.