Überladen des += Operators

Schnelle objektorientierte, kompilierende Programmiersprache.
Benutzeravatar
cloidnerux
Moderator
Beiträge: 3125
Registriert: Fr Sep 26, 2008 4:37 pm
Wohnort: Ram (Gibts wirklich)

Überladen des += Operators

Beitrag von cloidnerux » Sa Apr 25, 2009 5:04 pm

Also, ich will den += Operator in C++ überladen.
Nur verstehe ich nciht ganz wie das Funktioniert
Wie wird der Aufgerufen und was soll er zurückgeben?

Google schweigt sich Tot darüber.

MfG cloidnerux
Redundanz macht wiederholen unnötig.
quod erat expectandum

Benutzeravatar
fat-lobyte
Beiträge: 1398
Registriert: Sa Jul 05, 2008 12:23 pm
Wohnort: ::1
Kontaktdaten:

Re: Überladen des += Operators

Beitrag von fat-lobyte » Sa Apr 25, 2009 6:01 pm

Alle x= operatoren können nur als Memberfunktionen einer Klasse überladen werden. Du musst eine Klasse haben, für das ein += sinnvoll ist.
Die Syntax sieht so aus:

Code: Alles auswählen

<Rückgabewert> operator += (<AndererTyp> <anderesObjekt>) 
Ein kleines Beispiel

Code: Alles auswählen

#include <iostream>


struct MeineKlasse 
{
    int val;

    // konstruktor, objekt wir mit int initialisiert
    MeineKlasse(int _val)
     : val(_val)
    {}

    // ueberlade den += operator
    MeineKlasse& operator += (int other)
    { val += other; return *this; }
};

// ueberlade den stream operator fuer ostream, damit wir cout benutzen koennen
std::ostream& operator << (std::ostream& os, const MeineKlasse& k)
{ return os<<k.val; }

int main()
{
    MeineKlasse mein_objekt(5);        
    std::cout<<"mein_objekt ist "<<mein_objekt<<'\n'; // verwende stream operator

    // verwende += operator
    mein_objekt += 22;

    std::cout<<"mein_objekt ist jetzt "<<mein_objekt<<'\n';
    return 0;
};

Und so kann man in C++ für den Preis einer recht "unintuitive" Syntax bei der deklaration eine recht Hübsche und intuitive Syntax bei der verwendung erzeugen.
Wobei man dazusagen muss, dass die Syntax nur auf den ersten blick unintuitiv erscheint. Wenn man drüber nachdenkt merkt man, dass die Syntax doch ziemlich logisch ist.

Edit: übrigens, google schweigt sich nicht tot darüber, such nach "c++ operator overloading" und stell davor die Suche auf Englisch das gibt bessere Ergebnisse. Einer davon ist die C++ FAQ-Lite, eine sehr gute und informative Seite über mögliche Fehlerquellen in c++:
http://www.parashift.com/c++-faq-lite/o ... ading.html
Haters gonna hate, potatoes gonna potate.

Benutzeravatar
cloidnerux
Moderator
Beiträge: 3125
Registriert: Fr Sep 26, 2008 4:37 pm
Wohnort: Ram (Gibts wirklich)

Re: Überladen des += Operators

Beitrag von cloidnerux » Sa Apr 25, 2009 6:10 pm

Also, der += wird sozusoagen als "=" operator angesehn, der aus einem übergebenen objekt einen wert erzeugt und dem Objekt zuweißt?

//Edit:
Hab hier was gutes dazu gefunden: http://tutorial.schornboeck.net/operato ... ladung.htm

//Edit2:
Mein Compiler meldet mit bei folgendem Aufruf einen Fehler:

Code: Alles auswählen

static hexstring^ operator +=(hexstring^ a);
Und zwar:

Code: Alles auswählen

error C2805: Binärer Operator '+=' hat zu wenig Parameter
Wieso?
Zuletzt geändert von cloidnerux am Sa Apr 25, 2009 6:21 pm, insgesamt 1-mal geändert.
Redundanz macht wiederholen unnötig.
quod erat expectandum

nufan
Wiki-Moderator
Beiträge: 2558
Registriert: Sa Jul 05, 2008 3:21 pm

Re: Überladen des += Operators

Beitrag von nufan » Sa Apr 25, 2009 6:21 pm

Auf Xin's Homepage gibts eine schöne Erklärung dazu.

Eine Frage hab ich aber noch dazu:
Mein Wissen über C++ beschränkt sich noch eher auf die Theorie. Deshalb versteh ich nicht, wie man in der Methode auf private-Variablen der übergebenen Referenz zugreifen kann? Ich wüsste da nichts Besseres als set und get Methoden zu schreiben.

Benutzeravatar
fat-lobyte
Beiträge: 1398
Registriert: Sa Jul 05, 2008 12:23 pm
Wohnort: ::1
Kontaktdaten:

Re: Überladen des += Operators

Beitrag von fat-lobyte » Sa Apr 25, 2009 6:53 pm

cloidnerux hat geschrieben:Also, der += wird sozusoagen als "=" operator angesehn, der aus einem übergebenen objekt einen wert erzeugt und dem Objekt zuweißt?
Nur "logisch". Also gedanklich passiert das. Tatsächlich wird auf das Objekt schlicht und einfach die Funktion mit dem namen "operator +=", und mit einem internen this zeiger (den man nicht sieht) aufgerufen, und damit der interne wert erhöht.
Soweit ich weiß wird kein temporäres objekt erzeugt.
cloidnerux hat geschrieben://Edit2:
Mein Compiler meldet mit bei folgendem Aufruf einen Fehler:

Code: Alles auswählen

static hexstring^ operator +=(hexstring^ a);
Und zwar:

Code: Alles auswählen

error C2805: Binärer Operator '+=' hat zu wenig Parameter
Wieso?
Also erstmal versteh ich nicht was genau das ^ soll. Zweitens hast du etwas zu wenig kontext angegeben, bitte zeichne ein ungefähres bild von hexstring, und wo es verwendet wird.
dani93 hat geschrieben:Deshalb versteh ich nicht, wie man in der Methode auf private-Variablen der übergebenen Referenz zugreifen kann?
Tatsächlich hatte ich zuerst die Klasse als "class" definiert und die Membervariable auf private gesetzt. Dafür habe ich aber auch den überladenen stream operator als "friend" einauen müssen, und das wollte ich wegen etwaiger Verwirrungen vermeiden.
Als Struct definiert sind alle variablen automatisch public, es sei denn du führst explicit private oder protected zugriffsbeschränkungen ein.
Oder habe ich deine Frage missverstanden?
dani93 hat geschrieben: Ich wüsste da nichts Besseres als set und get Methoden zu schreiben.
Das wäre die Java variante, getters und setters für jede kleine mini-variable. Glücklicherweise kann man in C++ intuitiveren Code schreiben.
dani93 hat geschrieben: Mein Wissen über C++ beschränkt sich noch eher auf die Theorie.
Wieso denn das? Eine Sprache rein theoretisch zu lernen bringt nicht viel. Wenn du schon so topmotiviert bist und das ganze theoretisch machst, dann mach doch gleich ein "begleitendes" kleines Projekt dazu. Dabei wendest du immer das neu gelernte an. Ich kann dir zwar versprechen, dass du nur Müllcode fabrizieren wirst für den du dich später schämst (so wars zumindest bei mir), aber wenigstens lernst du einiges dabei.
Haters gonna hate, potatoes gonna potate.

Benutzeravatar
cloidnerux
Moderator
Beiträge: 3125
Registriert: Fr Sep 26, 2008 4:37 pm
Wohnort: Ram (Gibts wirklich)

Re: Überladen des += Operators

Beitrag von cloidnerux » Sa Apr 25, 2009 6:55 pm

Unter VC++ gibt es die möglichkeit etwas als eigenschaft zu definieren die eine get funktion hat, die automatisch aufgerufen wird wenn man darauf zugreift.

Aber ich habe auch ncoh eine Frage:
KAnn man den "=" operator so überladen, das er der Classe z.B einen Int wert zuweiß, alos ungefähr so:

Code: Alles auswählen

hexstring^ operator =(int data);
Weil bie mir meldet er bei diesen Aufruf keinen fehler, aber wenn cih versuche nun einem Objekt dieser Klasse einen Int wert zuzuweisen meldet er mir immer:

Code: Alles auswählen

error C2440: '=': 'int' kann nicht in 'hexstring ^' konvertiert werden
Wieso?
Redundanz macht wiederholen unnötig.
quod erat expectandum

nufan
Wiki-Moderator
Beiträge: 2558
Registriert: Sa Jul 05, 2008 3:21 pm

Re: Überladen des += Operators

Beitrag von nufan » Sa Apr 25, 2009 7:05 pm

fat-lobyte hat geschrieben:Tatsächlich hatte ich zuerst die Klasse als "class" definiert und die Membervariable auf private gesetzt. Dafür habe ich aber auch den überladenen stream operator als "friend" einauen müssen, und das wollte ich wegen etwaiger Verwirrungen vermeiden.
Als Struct definiert sind alle variablen automatisch public, es sei denn du führst explicit private oder protected zugriffsbeschränkungen ein.
Oder habe ich deine Frage missverstanden?
Ja. Ich hätte wohl genau sagen sollen, dass ich mich auf das Beispiel mit *= von Xin's Homepage beziehe.

Code: Alles auswählen

class Fraction
{
  private:
    int Numerator;
    int Denominator;
  public:
    Fraction( int num, int den ) : Numerator( num ), Denominator( den ) {}
    Fraction & operator *=( Fraction & rhs );
};

Fraction & Fraction::operator *=( Fraction & rhs )
{
  Numerator   *= rhs.Numerator;
  Denominator *= rhs.Denominator;
  return *this;
}
fat-lobyte hat geschrieben:Das wäre die Java variante, getters und setters für jede kleine mini-variable. Glücklicherweise kann man in C++ intuitiveren Code schreiben.
Mir wurde gesagt das sei Verkapselung, eines der Grundprinzipien der OOP. Wahrscheinlich aber im Hinblick auf die kommenden Java-Jahre.
fat-lobyte hat geschrieben:Wieso denn das? Eine Sprache rein theoretisch zu lernen bringt nicht viel. Wenn du schon so topmotiviert bist und das ganze theoretisch machst, dann mach doch gleich ein "begleitendes" kleines Projekt dazu. Dabei wendest du immer das neu gelernte an. Ich kann dir zwar versprechen, dass du nur Müllcode fabrizieren wirst für den du dich später schämst (so wars zumindest bei mir), aber wenigstens lernst du einiges dabei.
Allzu viel kann ich noch nicht. Das sind eher die unteren Sachen. Das würde ein ziemliches C/C++ durcheinander werden ;)
Aber es stimmt schon. Ich sollte mehr üben...

Benutzeravatar
fat-lobyte
Beiträge: 1398
Registriert: Sa Jul 05, 2008 12:23 pm
Wohnort: ::1
Kontaktdaten:

Re: Überladen des += Operators

Beitrag von fat-lobyte » Sa Apr 25, 2009 7:10 pm

cloidnerux hat geschrieben:Unter VC++ gibt es die möglichkeit etwas als eigenschaft zu definieren die eine get funktion hat, die automatisch aufgerufen wird wenn man darauf zugreift.
Bitte nimm Abstand von Compilererweiterungen. Wenn du auf deine VC++ Erweiterungen vermeidest, und ich meine GNU Erweiterungen kommen wir auf einen grünen Ast und können portabel Programmieren.
cloidnerux hat geschrieben:Aber ich habe auch ncoh eine Frage:
KAnn man den "=" operator so überladen, das er der Classe z.B einen Int wert zuweiß, alos ungefähr so:

Code: Alles auswählen

hexstring^ operator =(int data);
Weil bie mir meldet er bei diesen Aufruf keinen fehler, aber wenn cih versuche nun einem Objekt dieser Klasse einen Int wert zuzuweisen meldet er mir immer:

Code: Alles auswählen

error C2440: '=': 'int' kann nicht in 'hexstring ^' konvertiert werden
Wieso?
Ja, kann man. Erstens kannst du explizit den = operator überladen. Das muss allerdings wieder eine Memberfunktion der Klasse sein.
Zweite Möglichkeit: der Konstruktor. Wenn du einen Konstruktor hast, der eine bestimmte Variable als Parameter nimmt, dann kann man den Operator = auch mit der Klasse verwenden. ACHTUNG! Hier wird allerdings ein temporäres objekt aufgestellt! Sieh dir mal die zweite Version meines beispielsprogramms:

Code: Alles auswählen

#include <iostream>


struct MeineKlasse 
{
    int val;

    // konstruktor, objekt wir mit int initialisiert
    MeineKlasse(int _val)
     : val(_val)
    { std::cout<<"Constructed\n";}

    // ueberlade den += operator
    MeineKlasse& operator += (int other)
    { val += other; return *this; }
        
    ~MeineKlasse()
    { std::cout<<"Destructed\n";}
};

// ueberlade den stream operator fuer ostream, damit wir cout benutzen koennen
std::ostream& operator << (std::ostream& os, const MeineKlasse& k)
{ return os<<k.val; }

int main()
{
    MeineKlasse mein_objekt = 5;        
    std::cout<<"mein_objekt ist "<<mein_objekt<<'\n'; // verwende stream operator

    // hier wird das alte objekt zerstört, ein neues erstellt und dann
    // zugewiesen
    mein_objekt = 11;

    std::cout<<"mein_objekt ist jetzt "<<mein_objekt<<'\n';
    return 0;
};
AN DEINEM CODE IST NOCH WAS ANDERES FALSCH! Bitte mehr code posten.
Kannst du mir bitte bitte sagen was das ^ da macht??
Und poste bitte den Code deiner "hexstring" Klasse!
Haters gonna hate, potatoes gonna potate.

Benutzeravatar
cloidnerux
Moderator
Beiträge: 3125
Registriert: Fr Sep 26, 2008 4:37 pm
Wohnort: Ram (Gibts wirklich)

Re: Überladen des += Operators

Beitrag von cloidnerux » Sa Apr 25, 2009 7:14 pm

Also erstmal die ^ sind da weil es eine refernc klasse ist ....(.NET kram)
Ich Programmiere damit weil es sein muss.
hexstring.h:

Code: Alles auswählen

//hextsring.h
//stellt einen hexstring zur verfügung

#ifndef HEXSTRING_H
#define HEXSTRING_H

ref class hexstring
{
private:
	System::String^ hex;
public:

	System::String^ get() {
		return hex;
	};

	property System::String^ default[int] {
		System::String^ get(int idx);
		//void set(int idx, hexstring^ data);
		//void set(int idx, int data);
		//void set(int idx, char data);
		void set(int idx, System::String^ binärdata);
	}

	void set(int data);
	void set(System::String^ data);

	hexstring(int data);
	hexstring(System::String^ binärdata);
	
	void add_data(int data);
	void add_data(System::String^ data);

	static hexstring^ operator +(hexstring^ a, hexstring^ b);
	static hexstring^ operator +(hexstring^ a, int data);
	static hexstring^ operator +(hexstring^ a, System::String^ binärdata);

	hexstring^ operator =(const char *data);
	hexstring^ operator =(hexstring^ a);
	hexstring^ operator =(int data);
	hexstring^ operator =(System::String^ binärdata);
	hexstring^ operator =(wchar_t *data);

	hexstring^ operator +=(hexstring^ a);
	hexstring^ operator +=(int data);
	hexstring^ operator +=(System::String^ binärdata);

	static bool operator ==(hexstring^ a, hexstring^ b);
	static bool operator ==(hexstring^ a, int data);
	static bool operator ==(hexstring^ a, System::String^ binärdata);
};
#endif
hexstrng.cpp:

Code: Alles auswählen

//hexstring.cpp
//Definiert ale funktionen aus hextsring.h

#include "stdafx.h"
#include "hexstring.h"

using namespace System;


//
///////////////////////////////////////////
//Memberfunktionen

wchar_t tohex(wchar_t number)
{
	if(number>15)
	{
		//MessageBox::Show("Nummer zu groß", "Hinweis");
		return 0;
	}
	else 
	{
		switch(number){
			case 0: return '0';
			case 1: return '1';
			case 2: return '2';
			case 3: return '3';
			case 4: return '4';
			case 5: return '5';
			case 6: return '6';
			case 7: return '7';
			case 8: return '8';
			case 9: return '9';
			case 10: return 'A';
			case 11: return 'B';
			case 12: return 'C';
			case 13: return 'D';
			case 14: return 'E';
			case 15: return 'F';
		}
	}
	return 'Z';
}

int toint(wchar_t number) 
{
	switch(number)
	{
		case '0': return 0;
		case '1': return 1;
		case '2': return 2;
		case '3': return 3;
		case '4': return 4;
		case '5': return 5;
		case '6': return 6;
		case '7': return 7;
		case '8': return 8;
		case '9': return 9;
		case 'A': return 10;
		case 'B': return 11;
		case 'C': return 12;
		case 'D': return 13;
		case 'E': return 14;
		case 'F': return 15;
	}
	return 0;
}
		
System::String^ chartohex(unsigned char a)
{
	String^ result;
	result=tohex(a/16).ToString();
	result+=tohex(a%16).ToString();
	return result;
}

String^ inttohex(unsigned long i)
{
	String^ result="";
	unsigned long tmp = i;
	for(int i = 7; i > 0; i--)
	{
		result+=tohex(tmp/(16^i));	//Wie häufig kommt 16î vor?
		tmp=(tmp%16^i);				//Den rest der Division speichern
	}
	result+=tohex(tmp);				//Den rest in result speichern
	return result;
}

String^ stringtohex(System::String^ binärdata)
{
	String^ tmp;
	for(int i=0; i < binärdata->Length;i++)
	{
		tmp+=chartohex(binärdata[i]);
	}
	return tmp;
}

int hextoint(String^ hexstring)
{
	int tmp=0;
	for(int i=0; i<hexstring->Length; i+=2)
	{
		tmp+=(toint(hexstring[i]<<4)+toint(hexstring[i+1]));
	}
	return tmp;
}

//
///////////////////////////////////////////////////
//Konstruktor

hexstring::hexstring(int data)
{
   hex = inttohex(data);
}

hexstring::hexstring(String^ binärdata)
{
	hex = stringtohex(binärdata);
}

//
/////////////////////////////////////////////////
//Funktionen zum Manipulieren des Inhaltes des Hexstrings

void hexstring::add_data(int data)
{
	hex += inttohex(data);
}

void hexstring::add_data(String^ binärdata)
{
	hex+=stringtohex(binärdata);
}


void hexstring::set(int data)
{
	hex = inttohex(data);
}

void hexstring::set(String ^data)
{
	hex = stringtohex(data);
}

//
/////////////////////////////////////////////////
//Indexer:

String^ hexstring::default::get(int idx)			//gibt das Zeichenpaar für das Byte an stelle idx aus
{
	if((idx*2)>hex->Length) return "00";
	else return hex->Substring(idx*2, 2);
}

//void hexstring::default::set(int idx, hexstring^ data)
//{
//	hex->Replace(hex->Substring(idx*2, data->hex->Length), data);
//}
//
//void hexstring::default::set(int idx, int data)
//{
//	hex->Replace(hex->Substring(idx*2, 8), inttohex(data));
//}
//
//void hexstring::default::set(int idx, char data)
//{
//	hex->Replace(hex->Substring(idx*2,2), chartohex(data));
//}

void hexstring::default::set(int idx, String^ binärdata)
{
	hex->Replace(hex->Substring(idx*2, binärdata->Length), stringtohex(binärdata));
}

//
/////////////////////////////////////////////////
//Operatordefinitionen

//+:

hexstring^ hexstring::operator +(hexstring ^a, hexstring ^b)
{
	return gcnew hexstring(a->hex + b->hex);
}

hexstring^ hexstring::operator +(hexstring ^a, int data)
{
	return gcnew hexstring(a->hex + inttohex(data));
}
hexstring^ hexstring::operator +(hexstring ^a, System::String ^binärdata)
{
	return gcnew hexstring(a->hex + stringtohex(binärdata));
}

//
//////////////////////////////////////////
//+=:

hexstring^ hexstring::operator +=(hexstring ^a)
{
	hex+=a->hex;
	return this;
}

hexstring^ hexstring::operator +=(int data)
{
	hex += inttohex(data);
	return this;
}

hexstring^ hexstring::operator +=(System::String ^binärdata)
{
	hex += stringtohex(binärdata);
	return this;
}

//
//////////////////////////////////////////
//=:

hexstring^ hexstring::operator =(hexstring ^a)
{
	hex = a->hex;
	return this;
}

hexstring^ hexstring::operator =(int data)
{
	hex = inttohex(data);
	return this;
}

hexstring^ hexstring::operator =(String ^binärdata)
{
	hex = stringtohex(binärdata);
	return this;
}

hexstring^ hexstring::operator =(wchar_t *data)
{
	hex = Convert::ToString(*data);
	return this;
}

hexstring^ hexstring::operator =(const char *data)
{
	hex = Convert::ToString(*data);
	return this;
}

//
//////////////////////////////////////////
//==:

bool hexstring::operator ==(hexstring^ a, hexstring^ b)
{
	if(a->hex == b->hex) return true;
	else return false;
	return false;
}

bool hexstring::operator ==(hexstring^ a, int data)
{
	if(a->hex == inttohex(data)) return true;
	else return false;
	return false;
}

bool hexstring::operator ==(hexstring^ a, String^ binärdata)
{
	if(a->hex == stringtohex(binärdata))return true;
	else return false;
	return false;
}
Redundanz macht wiederholen unnötig.
quod erat expectandum

Benutzeravatar
fat-lobyte
Beiträge: 1398
Registriert: Sa Jul 05, 2008 12:23 pm
Wohnort: ::1
Kontaktdaten:

Re: Überladen des += Operators

Beitrag von fat-lobyte » Sa Apr 25, 2009 7:23 pm

dani93 hat geschrieben: Ja. Ich hätte wohl genau sagen sollen, dass ich mich auf das Beispiel mit *= von Xin's Homepage beziehe.
Achso... Naja das ist etwas, was ich ein wenig obskur in C++ finde. Da das andere Objekt ja vom "gleichen" typ ist wie das jetzige, wird auf die Variablen auch nur quasi "intern" zugegriffen. Das bedeutet, private bezieht sich nicht auf das Objekt selbst (also auf Zeiger auf das Objekt) sondern auf den Typ des Objekts. Das gilt aber nur für Objekte gleichen Typs. Ich bin mir nichtmal sicher, ob man das auch mit funktionen machen kann die nicht der Konstruktor sind.
dani93 hat geschrieben:Mir wurde gesagt das sei Verkapselung, eines der Grundprinzipien der OOP. Wahrscheinlich aber im Hinblick auf die kommenden Java-Jahre.
Darf ich mal fragen, wozu man eigentlich getters und setters definiert, anstatt die Variable gleich Public zu machen?? Bei Kapselung gehts darum dinge Abzukapseln, was bei get/set eindeutig nicht der Fall ist. Eine andere geschichte sind allerdings "read only" member. Hier kann man durch getVariable() const Funktionen schon dinge Abkapseln.
Haters gonna hate, potatoes gonna potate.

Antworten