[]-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!