Twitter und Facebook-Anbindung
X
Tweet Follow @twitterapi
!!! Anbindung an twitter und facebook öffnen !!!

Wenn Ihnen mein Online-Buch gefällt,
dann bedanken Sie sich doch mit einer kleinen Spende...

23.3 Berechnungen (+, -, ++, --)

23.3 Berechnungen (+, -, ++, --)

Da nun eine Grundlage geschaffen ist, komme ich jetzt zu den Berechnungsoperatoren. Jene sind zum Teil unär und zum Teil binär. Ich werde dann jeweils darauf hinweisen, um was es sich handelt.

Zuerst werde ich die Klassendefinition in der Header-Datei, um folgende Einträge, im "public" Bereich, erweitern.

 1
 2
 3
 4
 5
 6
 7
 8
 9
					
		// unär
		CInteger	operator+() const;	// Vorzeichen
		CInteger	operator-() const;	// Vorzeichen
		CInteger&	operator++(void);	// linksseitig
		CInteger	operator++(int);	// Rechtsseitig

		// binär
		CInteger	operator+(const CInteger&) const;
		CInteger	operator+(const int&) const;
					

Hier scheint es auf den ersten Blick Dopplungen zu geben, aber wie Sie evtl. schon an den Kommentaren erkennen können, haben diese vermeintlichen Dopplungen ihre Berechtigung (je nachdem, was man vor hat). Was dahinter steckt, werden Sie gleich sehen. Des weiteren gibt es jetzt Methoden, hinter welchen ein "const" steht und Sie fragen sich jetzt bestimmt, was es damit auf sich hat. Nun, das ist zum einen rein optional und soll zum anderen dem Benutzer dieser Methoden zeigen, das durch diese Methoden das eigentliche Objekt unberührt bleibt. Dies ist u.a. eine wichtige Eigenschaft von binären Operatoren. Kommen wir nun zur Implementierung.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
					
// Vorzeichen /////////////////////////////////////////////////////////////////
CInteger CInteger::operator+(void) const {
	return *this;
}

CInteger CInteger::operator-(void) const {
	return CInteger(-this->m_iValue);
} // operator- ////////////////////////////////////////////////////////////////

// ...

// Ermöglicht wird jetzt z.B. so etwas
CInteger oObjekt1(5);
CInteger oObjekt2(7);

oObjekt1			= +oObjekt2;
oObjekt1			= -oObjekt1;

// oder auch
CInteger* pZeigerAufObjekt1	= new CInteger(5);
CInteger* pZeigerAufObjekt2	= new CInteger(7);

*pZeigerAufObjekt1		= +(*pZeigerAufObjekt2);
*pZeigerAufObjekt2		= -(*pZeigerAufObjekt2);

delete pZeigerAufObjekt1;
delete pZeigerAufObjekt2;
					

Diese zwei Methoden erlauben es also, positive oder negative Vorzeichen zu benutzen. Wie bereits erwähnt, wird dabei aber nicht der eigene Wert manipuliert, sondern eine manipulierte Kopie zurückgegeben. Warum gibt man jetzt aber keine Referenz zurück wie vorhin? Überlegen wir uns folgende Situation. Sie wollen schreiben "oA = -oB". Jetzt wird zuerst die Operatormethode "-" des Objektes "oB" aufgerufen, welche ein neues Objekt (nennen wir es mal "oX") zurück gibt. Anschließend wird die Operatormethode "="; des Objektes "oA" aufgerufen und eine Kopie von "oX" übergeben. Jetzt braucht zwar die Operatormethode "=" eine Referenz, aber Vorsicht, was ist damit gemeint? Der Referenzierungsoperator hat etwas mit call-by-reference zu tun hat und wenn man so etwas baut, übergibt man die Variable normal und Dereferenziert sie nicht extra (in dem Fall müsste die Methode ja ein Pointer entgegen nehmen). Wenn Sie jetzt Kopfschmerzen haben, dann ist das normal, denn auch darüber muss man eine weile Nachdenken, bevor man es einsieht.

Die erste Methode ist reine Kür, da lediglich das Objekt selbst zurückgegeben wird. Aber Moment mal, jetzt wird das Objekt selbst zurückgegeben und vorhin war es eine Referenz? Das hat schon seine Richtigkeit, denn erinnern Sie sich. Vorhin wollte ich keine Kopie des Objektes erzeugen, sondern wirklich die Referenz haben. Jetzt will ich aber eine Kopie und wenn man im Debugg-Modus ist, wird man evtl. auch sehen, dass nach dem "return", der Kopierkonstruktor aufgerufen wird. Ich kann es nicht oft genug sagen, aber man muss sich immer vor Augen halten, dass eine Referenz und eine Adresse nicht immer das gleiche sind. Es kommt echt darauf an, in welchem Kontext man diesen Begriff verwendet. Jetzt könnten Sie sich aber fragen, wenn wir hier eh nichts gemacht wird, warum brauche ich so etwas überhaupt. Die Antwort ist, dass es später solche Ausdrücke wie "oA = +oB" geben könnte und dann ist dieser Operator notwendig.

Die zweite Methode ist dazu da, den negativen Wert zurückzugeben. Auch hier wird nicht das eigene Objekt manipuliert, sondern nur eine manipulierte Kopie zurückgegeben. Genau genommen erzeuge ich mir sogar eine Kopie und gebe sie zurück, welche dann wiederum kopiert wird, da mein in der Methode erzeugtes Objekt, nach dem Methodenaufruf, freigegeben wird.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
					
// Inkrementieren /////////////////////////////////////////////////////////////
CInteger& CInteger::operator++(void) {
	this->m_iValue++;
	return *this;
}

CInteger CInteger::operator++(int) {
	CInteger oResult(this->m_iValue);
	this->m_iValue++;
	return oResult;
} // operator++ ///////////////////////////////////////////////////////////////

// ...

// Ermöglicht wird jetzt z.B. so etwas
CInteger oObjekt1(5);
CInteger oObjekt2(7);

oObjekt1			= ++oObjekt2;
oObjekt1			= oObjekt2++;

// oder auch
CInteger* pZeigerAufObjekt1	= new CInteger(5);
CInteger* pZeigerAufObjekt2	= new CInteger(7);

*pZeigerAufObjekt1		= ++(*pZeigerAufObjekt2);
*pZeigerAufObjekt2		= (*pZeigerAufObjekt2)++;

delete pZeigerAufObjekt1;
delete pZeigerAufObjekt2;
					

Die erste Methode implementiert den linksseitigen "++" Operator. Hier wird erst der eigene Wert um eins erhöht und anschließend zurückgegeben. Da hier der eigene Wert des Objektes modifiziert wird, ist diese Methode nicht mit "const" deklariert und es wird wieder die eigene Referenz zurückgegeben (aus mittlerweile bekannten Gründen).

Die zweite Methode implementiert den rechtsseitigen "++" Operator. Hier wird erst der Wert zurück gegeben und anschließend der eigene Wert um eins erhöht. Um dies zu realisieren, benötige ich also eine Kopie des Originals, welches dann auch zurückgegeben wird und kann anschließend den Wert der Membervariable um 1 erhöhen. Da ich wie gesagt hier nur eine Kopie zurück gebe, ist der Rückgabeparameter auch anders, als beim linksseitigen Inkrementierungsoperator.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
					
// Addition ///////////////////////////////////////////////////////////////////
CInteger CInteger::operator+(const CInteger& oIntRight) const {
	return CInteger(this->m_iValue + oIntRight.m_iValue);
}

CInteger CInteger::operator+(const int& iIntRight) const {
	return CInteger(this->m_iValue + iIntRight);
} // operator+ ////////////////////////////////////////////////////////////////

// ...

// Ermöglicht wird jetzt z.B. so etwas
CInteger oObjekt1(5);
CInteger oObjekt1(7);
CInteger oObjekt3(9);

oObjekt1			= oObjekt2 + oObjekt3;
oObjekt1			= oObjekt2 + 15;

// oder auch
CInteger* pZeigerAufObjekt1	= new CInteger(5);
CInteger* pZeigerAufObjekt2	= new CInteger(7);
CInteger* pZeigerAufObjekt3	= new CInteger(9);

*pZeigerAufObjekt1		= *pZeigerAufObjekt2 + *pZeigerAufObjekt3;
*pZeigerAufObjekt2		= *pZeigerAufObjekt2 + 15;

delete pZeigerAufObjekt1;
delete pZeigerAufObjekt2;
delete pZeigerAufObjekt3;
					

In der ersten Methode habe ich jetzt den eigentlichen "+" Operator implementiert, mit welchem ich jetzt zwei Objekte miteinander addieren kann. Die anderen Berechnungsmethoden (-, *, /, %, &, | usw.), sähen äquivalent aus. Berechne ich "oA + oB", wird der die Operatormethode "+" von "oA" aufgerufen und der Übergabeparameter "oIntRight" wäre dann "oB". Da hier das eigene Objekt nicht verändert wird, ist diese Methode als konstant definiert und muss logischerweise wieder ein neues Objekt zurück geben.

Die Zweite Methode ist fast so ähnlich, nur das ich hier zusätzlich erlaube, dass man mein Objekt auch mit einem Integer addieren kann. Entsprechend modifiziert, ist dies auch für andere Datentypen möglich.

Zum Seitenanfang
Zum Inhaltsverzeichnis

© Copyright by Thomas Weiß, 2009 - 2012