[]
-Operators kein lvalue, an den etwas zugewiesen werden
darf. Ein Ausdruck der Form objekt[1] = ...
wäre dann nicht möglich.
Dasselbe gilt für andere Operatoren, wenn man deren Ergebnis möglicherweise als lvalue verwenden möchte.
Dazu ein kleines Beispiel, mit dem das Überladen des []
-Operators
gezeigt wird:
// Time-stamp: "(15.11.01 16:10) intarr.cpp [Klaus Wachtler (aw38)]" // // demonstriert eine Klasse für int-Felder // mit dynamischer Allokierung: // Bei jedem Zugriff hinter das bislang allokierte // Feld wird automatisch neu allokiert. #include <iostream> #include <cstdlib> using namespace std; class intarr { private: int *p; // Zeiger auf das eigentliche Feld size_t l; // die allokierte Länge void resize( size_t index ); public: intarr( void ); ~intarr( void ); int &operator[]( long index ); }; // Der Konstruktor sorgt für jedes intarr-Objekt für // die Initialisierung (anfangs 0 Feldelemente). intarr::intarr( void ) { p = NULL; l = 0; } // Der Destruktor sorgt für jedes intarr-Objekt für // die Freigabe des allokierten Feldes. intarr::~intarr( void ) { if( (p) ) // wurde überhaupt schon etwas allokiert? { free( p ); } } // Der Operator [] wird mit einer Funktion überladen, die: // a) ein Unterschreiten des Feldes (index<0) abfängt, und // b) das Feld mit intarr::resize() ggf. verlängert, und dann // c) eine Referenz auf das index'te Element des Objekts liefert. int &intarr::operator[]( long index ) { if( (index<0) ) // Unterschreitung abfangen { cerr << "So geht das nicht!" << endl; cerr << "intarr::operator[]( long index ): (index==" << index << "), es muss aber (index>=0) sein!" << endl; exit( 1 ); } resize( index ); // Das Feld ggf. verlängern return p[index]; // weil diese Funktion als Referenz // vereinbart ist (int &), wird hier // nicht der Wert eines Feldelements // geliefert, sondern eine Referenz darauf. } // resize() sorgt dafür, dass ein Feldelement mit der Nummer (index) // verwendet werden kann. // Wenn index ausserhalb des allokierten Bereichs liegt, // wird das Feld mit realloc() entsprechend verlängert. // Der neue Bereich wird mit (0)en vorbesetzt. void intarr::resize( size_t index ) { if( (index >= l) ) { // der gewünschte Index liegt hinter der // momentanen Feldgrenze, also muss das Feld // vergrössert werden: p = (int *)realloc( p, (++index)*sizeof(*p) ); // die neugewonnenen Elemente erstmal auf 0 setzen: while( l<index ) { p[l++] = 0; } } } // Testprogramm: // Ein Feld (ohne Angabe von Grenzen!) wird als Variable feld // vereinbart. Dann werden einige Elemente ( feld[4], feld[3] ) // belegt und feld[0] bis feld[5] dann ausgegeben. // Zuletzt wird durch einen negativen Index ein Unterlauf des // Feldes und damit ein Programmabbruch provoziert. int main( int nargs, char *args[] ) { intarr feld; // Ein Objekt der Klasse wird erzeugt // (ohne Elemente) feld[4] = 44; // feld[0] bis feld[4] werden allokiert, // feld[4] wird mit 44 beschrieben, der Rest mit 0 feld[3] = 3; // feld[3] wird überschrieben for( int i=0; i<=5; i++ ) { // feld[0] bis feld[4] werden ausgegeben, // dann wird feld[5] mit realloc() geschaffen, mit 0 // vorbesetzt und auch ausgegeben: cout << "feld[" << i << "] = " << feld[i] << endl; } feld[-5] = 12; // erzeugt Programmabbruch mit exit() return 0; }
Die zugehörige Ausgabe lautet:
feld[0] = 0 feld[1] = 0 feld[2] = 0 feld[3] = 3 feld[4] = 44 feld[5] = 0 So geht das nicht! intarr::operator[]( long index ): (index==-5), es muss aber (index>=0) sein!