Top-Themen

AppleEntwicklungHardwareInternetLinuxMicrosoftMultimediaNetzwerkeOff TopicSicherheitSonstige SystemeVirtualisierungWeiterbildungZusammenarbeit

Aktuelle Themen

Administrator.de FeedbackApache ServerAppleAssemblerAudioAusbildungAuslandBackupBasicBatch & ShellBenchmarksBibliotheken & ToolkitsBlogsCloud-DiensteClusterCMSCPU, RAM, MainboardsCSSC und C++DatenbankenDatenschutzDebianDigitiales FernsehenDNSDrucker und ScannerDSL, VDSLE-BooksE-BusinessE-MailEntwicklungErkennung und -AbwehrExchange ServerFestplatten, SSD, RaidFirewallFlatratesGoogle AndroidGrafikGrafikkarten & MonitoreGroupwareHardwareHosting & HousingHTMLHumor (lol)Hyper-VIconsIDE & EditorenInformationsdiensteInstallationInstant MessagingInternetInternet DomäneniOSISDN & AnaloganschlüsseiTunesJavaJavaScriptKiXtartKVMLAN, WAN, WirelessLinuxLinux DesktopLinux NetzwerkLinux ToolsLinux UserverwaltungLizenzierungMac OS XMicrosoftMicrosoft OfficeMikroTik RouterOSMonitoringMultimediaMultimedia & ZubehörNetzwerkeNetzwerkgrundlagenNetzwerkmanagementNetzwerkprotokolleNotebook & ZubehörNovell NetwareOff TopicOpenOffice, LibreOfficeOutlook & MailPapierkorbPascal und DelphiPeripheriegerätePerlPHPPythonRechtliche FragenRedHat, CentOS, FedoraRouter & RoutingSambaSAN, NAS, DASSchriftartenSchulung & TrainingSEOServerServer-HardwareSicherheitSicherheits-ToolsSicherheitsgrundlagenSolarisSonstige SystemeSoziale NetzwerkeSpeicherkartenStudentenjobs & PraktikumSuche ProjektpartnerSuseSwitche und HubsTipps & TricksTK-Netze & GeräteUbuntuUMTS, EDGE & GPRSUtilitiesVB for ApplicationsVerschlüsselung & ZertifikateVideo & StreamingViren und TrojanerVirtualisierungVisual StudioVmwareVoice over IPWebbrowserWebentwicklungWeiterbildungWindows 7Windows 8Windows 10Windows InstallationWindows MobileWindows NetzwerkWindows ServerWindows SystemdateienWindows ToolsWindows UpdateWindows UserverwaltungWindows VistaWindows XPXenserverXMLZusammenarbeit

Überladen von Funktionen und Operatoren in C plus plus

Anleitung Entwicklung C und C++

Mitglied: Guenni

Guenni (Level 2) - Jetzt verbinden

31.12.2006, aktualisiert 26.05.2008, 12754 Aufrufe, 1 Kommentar

Normalerweise hat in jeder Programmiersprache jede Funktion ihren
eindeutigen Namen. Allgemein ausgedrückt hieße das:

Variable_Max_Integer = Max_Integer(5,7)
Variable_Max_Fließkomma = Max_Fließkomma(3.4,1.34)
usw.

In C++ ist es möglich, einen einzigen Funktionsnamen mehrmals zu
gebrauchen, vorausgesetzt, der Rückgabetyp und/oder der/die
Parametertyp(en) unterliegen einem unterschiedlichem Kontext.

Anhand dieser Kriterien sucht sich der Compiler die passende
Implementation der Funktion selber heraus. Die Implementation selber
wird vernachlässigt, die kann bei jeder Funktion gleich sein.

Zum Überladen von Operatoren mehr im 2. Kapitel

1. Funktionsüberladung
2. Operatorüberladung in Klassen
3. Ausgabe in Datei
4. Eingabe aus Datei
5. Ein Test-Script
6. Anhang – Ein Überladungstest

1. Funktionsüberladung

Wir möchten beispielsweise den Maximalwert von Variablen ermitteln.
Als Funktionsprototypnamen nehmen wir cmax, ermittelt werden soll
dabei der größere Wert zweier Argumente.

Funktionsprototyp für Ganzzahlvariablen:

int cmax(int,int);

Funktionsprototyp für Fließkommavariablen:

double cmax(double,double);

Funktionsprototyp für Zeichen:

char cmax(char,char);

Die Implementation ist für alle drei gleich:

Rückgabetyp cmax(argument_typ a, argument_typ b){

return a<b?b:a;

}

Der zusammengesetzte Operator prüft zuerst, ob a kleiner ist als b.
Wenn ja, gibt er b zurück, ansonsten a.

Somit haben wir den Funktionsnamen cmax zweimal überladen und brauchen künftig
nur noch eine Funktion, um den Maximalwert dreier versch. Datentypen zu
ermitteln. In der Praxis sieht es dann so aus:

int i_max = cmax(5,7);
double d_max = cmax(2.3,1.45);
char c_max = cmax('C','B');

printf("%d",i_max);
printf("%f",d_max);
printf("%c",c_max);

Im letzten Beispiel muß man sich den Ascii-Code in Erinnerung rufen:

A=Ascii-Code 65
B=Ascii-Code 66
C=Ascii-Code 67
usw.

Daher liefert die Funktion cmax "C" zurück, weil 67 größer ist als 66.


2.Operatorüberladung

Normalerweise benutzt man arithmetische Operatoren für das, wofür
sie nun mal da sind: Addition, Subtraktion usw. Einige Programmier/Script-
sprachen lassen diese Operatoren auch auf Zeichenketten zu, da kann man
Ausdrücke verwenden wie:

var s=" Text";
print/write "ein" + s

Ergebnis/Ausgabe: Ein Text

Um eine solche Syntax auch in C++ vorzunehmen, ist es nötig, arithmetische
Operatoren zu überladen. Überladen im Zusammenhang mit Operatoren
heißt nichts anderes, als dass man dem Operator mittels einer
Funktionsdefinition eine neue/andere Aufgabe zuweist.

Allerdings kann dieses nur in Verbindung mit Klassen passieren.

Operatoren liefern wie Funktionen ein Ergebnis zurück, daher werden sie
auch wie Funktionen definiert:

Rückgabetyp& operator+(Argumententyp&);

Wie bei Funktionen ist auch ein mehrmaliges Überladen von
Operatoren möglich, dazu später mehr.

Die Implementation kann, analog zu Methoden, innerhalb oder
außerhalb der Klasse liegen.

Wer mit C++ schon mal Zeichenketten verarbeitet oder manipuliert hat,
der weiß, wie mühselig es sein kann, besonders, wenn man mit Zeigern
auf Zeichenketten arbeitet.

Da liegt es nahe, dass man für zukünftige Programme eine Klasse für Zeichenketten
entwickelt und weiter pflegt, heißt, die Klasse Methode für Methode
erweitert, bis alle Bereiche abgedeckt sind, die zur Verarbeitung von
Zeichenketten nötig sind.

Ungeachtet dessen, ob eine solche Klasse bereits existiert, ist es
vielleicht interessant, sich selber mal dran zu setzen.

Unsere Klasse nennen wir einfach CString:

class CString{

};

Daten der Klasse werden mit dem Schlüsselwort private vor
Zugriff geschützt. Die Manipulation der Daten soll ja ausschließlich
von Methoden vorgenommen werden, die durch das Schlüsselwort public
dazu bestimmt sind.

class CString{

private:

Variablendeklaration

public:

Konstruktoren
Methoden
Destruktor
};

Der Einsatz von private und public ist hierbei mehrmals möglich:

class CString{

private:
Daten
public:
Konstruktoren
Destruktor
private:
noch mehr Daten
public
Methoden
usw.
};

Die Namen der Konstruktoren/ Destruktoren sind stets indentisch mit
dem Namen der Klasse. Dem Namen des Destruktors wird die Tilde
vorangestellt: ~Destruktor
Einen Rückgabetyp gibt es für beide nicht.

Anhand dieser Info können wir jetzt unsere Klasse aufbauen:

class CString{

private:
char *string; Zeiger auf eine Zeichenkette
int size;
Länge der Zeichenkette
public:
CString(); Standard-Konstruktor
CString(const char*);
Konstruktor mit Initialisierung
CString& operator+(CString&); Additions-Operator überladen, Objekt + Objekt
CString& operator+(const char*);
Additions-Operator nochmals überladen, Objekt + Zeichenkette
CString& operator=(CString&); Zuweisungs-Operator überladen
void CString_Print();
Ausgabe string
~CString(); //Destruktor
};

Die Implementierung der Methoden und Operatoren kann innerhalb oder
außerhalb der Klasse erfolgen. Erfolgt sie außerhalb, muß dazu der
der Scope-Operator :: benutzt werden.

Die Syntax der Konstruktoren/Destruktoren ist hierbei:

Klassenname::Konstruktor([argument]){

ToDo
}

bzw.

Klassenname::~Destruktor(){

ToDo
}

Die Syntax der Methoden/Operatoren:

Rückgabetyp& Klassenname::operator op/Methode([Parameter]){
ToDo
}

[] innerhalb () heißt, optional.

Der Standard-Konstruktor...

CString::CString(){
string=0;
size=0;
}
… erzeugt ein leeres Objekt.

Syntax im Programm: CString s;

Der Konstruktor mit Initialisierung initialisiert das Objekt mit Werten.
Interessant ist hierbei die Verwendung des Operators new.
Zur Speicherreservierung von Zeigern auf Zeichenketten wurde sonst
die Bibliothek malloc.h herangezogen, z.B.:

char *string;
string=(char*)malloc(sizeof(char)*String_Länge);

Das erledigt nun für uns new.

Der Konstruktor mit Initialisierung belegt die Variable(n) des
Objekts bei der Erzeugung mit Werten.

CString::CString(const char *s){
size = strlen(s);
string = new char[size + 1];
strcpy(string, s);
}

Syntax im Programm: CString s("Text");

Der Operator = weißt dem Objekt einen neuen Wert zu:

CString& CString::operator=(CString& k){
delete [] string;
string = new char[(size = k.size) + 1];
strcpy(string,k.string);
return *this;
}

Syntax im Programm: CString s; CString t("Text"); s=t;

Der Operator + wurde ja bei der Klassendefinition zweimal überladen:

Zum einen soll er einem Objekt Typ CString ein Objekt Typ CString
anhängen, zum anderen einem Objekt Typ CString einen String anhängen.

CString& CString::operator+(CString& k){
size += k.size;
char *s = new char[size + 1];
strcpy(s,string);
strcat(s,k.string);
delete [] string;
string = s;
return *this;
}

CString& CString::operator+(const char *k){
size += strlen(k);
char *s = new char[size + 1];
strcpy(s,string);
strcat(s,k);
delete [] string;
string = s;
return *this;
}

Syntax im Programm:

CString s("Ein"); CString t(" Text"); CString st=s+t;

CString s("Eine"); char t=" Demo"; CString st=s+t;

Die Methode CString_Print() gibt den Inhalt des Objekts
einfach nur aus:

void CString::CString_Print(){
cout << string << endl;
}

Syntax im Programm:

Objekt.CString_Print();

Der Destruktor ~CString gibt einfach den Speicher wieder frei:

CString:: ~CString()
{
delete[] string;
}

Der Destruktor wird nie aufgerufen, er erledigt seine Arbeit automatisch.

3. Ausgabe in Datei

Wie speichern wir nun den Inhalt unserer Klasse in eine Datei?

Ein Zugriff via Punktoperator "Schreibe s.string in Datei..." ist nicht
möglich, da die Variable string unter private deklariert wurde:

CString s("Ein Text");
ofstream datei("c:\test.txt",ios::out);
datei << s.string;

... schlägt also fehl,

datei << s; schlägt ebenso fehl, da mäkelt der Compiler, dass es für unseren
Typ Klasse und dem Operator << keine Übereinstimmung gibt. Na, dann
überladen wir den Operator doch einfach. Aber wie? Eine Überladung
innerhalb der Klasse legt als linken Operanden immer die Klasse fest:

CString& CString::operator<<(... ?

Auf der linken Seite sollte doch, im Sinne von cout << Variable, der
Ausgabestrom stehen.

Die Lösung liegt im Schlüsselwort friend. Hiermit wird das Klassenprinzip,
der Zugriff auf Daten nur durch klasseneigene Methoden, wieder
aufgehoben, indem einer anderen Klasse der Zugriff auf unsere Klasse
gewährt wird!! Wir sagen unserer Klasse also jetzt mal, vertraue der
Klasse ostream:

class CString{
private:

public:

friend ostream& operator<<(ostream &h, CString &s){
h << s.string;
return h;
}

};

Durch diese Überladung von << ist es nun möglich, ein Objekt vom
Typ CString in eine Datei zu schreiben:

CString s("Ein Text");
ofstream datei("c:\test.txt",ios::out);
datei << s;

4.Eingabe aus Datei

Es liegt nun nahe, dass der Eingabeoperator ebenso überladen werden muß,
damit wir Dateiinhalte in unser Objekt übertragen können:

const int PUFFER = 2048;
...
...
class CString{
...
public:
friend istream& operator>>(istream &h, CString &s){
char *puffer = new char[PUFFER + 1];
h.getline(puffer,PUFFER);
delete [] s.string;
s.string = new char[(s.size = h.count())+1];
strcpy(s.string,puffer);
delete [] puffer;
return h;
}

};

CString s;
ofstream datei("c:\test.txt",ios::in);
datei >> s;


5.Ein Testscript

Das folgende Script ist erfolgreich kompiliert mit Visual C++ 2005 Express Editition.
Es werden zwar 7 Warnmeldungen ausgegeben, die aber nur darauf hinweisen, dass
bestimmte Funktionen veraltet sind. Die produzierte EXE-Datei läßt sich problemlos
ausführen.


01.
#include <stdio.h> 
02.
#include <iostream> 
03.
#include <fstream> 
04.
#include <string.h> 
05.
const int PUFFER = 2048; 
06.
using namespace std; 
07.
 
08.
// Überladener Funktionsptototyp cmax 
09.
int cmax(int,int); 
10.
double cmax(float,float); 
11.
char cmax(char,char); 
12.
// Implementation der Funktionen 
13.
int cmax(int a, int b){ 
14.
 return a<b?b:a; 
15.
16.
double cmax(double a, double b){ 
17.
 return a<b?b:a; 
18.
19.
char cmax(char a,char b){ 
20.
 return a<b?b:a; 
21.
22.
// Eine Klasse String 
23.
class CString{ 
24.
 private: 
25.
		 char *string; 
26.
         int size;  
27.
 public: 
28.
        CString(); //Standard-Konstruktor 
29.
        CString(const char*); //Konstruktor mit Initialisierung 
30.
        CString& operator+(CString&); //Additions-Operator überladen, Objekt + Objekt 
31.
        CString& operator+(const char*); // Additions-Operator überladen, Objekt + Zeichenkette 
32.
		CString& operator=(CString&); // Zuweisungs-Operator überladen 
33.
        void CString_Print(); // Ausgabe CString 
34.
        ~CString(); //Destruktor 
35.
        friend ostream& operator<<(ostream &h, CString &s){ // Ausgabeoperator überladen 
36.
         h << s.string; 
37.
         return h; 
38.
39.
		friend istream& operator>>(istream &h,CString &s){ // Eingabeoperator überladen 
40.
		 char *puffer = new char[PUFFER + 1]; 
41.
		 h.getline(puffer,PUFFER); 
42.
		 delete [] s.string; 
43.
		 s.string = new char[(s.size = h.gcount())+1]; 
44.
		 strcpy(s.string,puffer); 
45.
		 delete [] puffer; 
46.
		 return h; 
47.
48.
 }; 
49.
 
50.
 
51.
 
52.
// Implementierung der Methoden 
53.
CString::CString(){ 
54.
 string=0; 
55.
 size=0; 
56.
57.
 
58.
CString::CString(const char *s){ 
59.
 size = strlen(s); 
60.
 string = new char[size + 1]; 
61.
 strcpy(string, s); 
62.
63.
 
64.
CString& CString::operator=(CString& k){ 
65.
 delete [] string; 
66.
 string = new char[(size = k.size) + 1]; 
67.
 strcpy(string,k.string); 
68.
 return *this; 
69.
70.
CString& CString::operator+(CString& k){ 
71.
 size += k.size; 
72.
 char *s = new char[size + 1]; 
73.
 strcpy(s,string); 
74.
 strcat(s,k.string); 
75.
 delete [] string; 
76.
 string = s; 
77.
 return *this;       
78.
}  
79.
CString& CString::operator+(const char *k){ 
80.
 size += strlen(k); 
81.
 char *s = new char[size + 1]; 
82.
 strcpy(s,string); 
83.
 strcat(s,k); 
84.
 delete [] string; 
85.
 string = s; 
86.
 return *this;       
87.
}  
88.
 
89.
void CString::CString_Print(){ 
90.
 cout << string << endl; 
91.
92.
 
93.
CString:: ~CString() 
94.
95.
  delete[] string; 
96.
97.
 
98.
int main(int argc, char *argv[]) 
99.
100.
    ofstream out("c:\\cstring.txt",ios::out); 
101.
	ifstream in("c:\\cstring.txt",ios::in); 
102.
	CString a("Ein "); 
103.
	CString b("Text"); 
104.
	CString c=a+b; 
105.
    CString d("Noch"); 
106.
    char e[64]=" ein Text"; 
107.
    CString f=d+e; 
108.
	CString g; 
109.
	c.CString_Print(); // Ausgabe: Ein Text 
110.
    f.CString_Print(); // Ausgabe: Noch ein Text 
111.
    printf("%d\n",cmax(5,7)); // Ausgabe: 7 
112.
    printf("%f\n",cmax(2.3,1.45)); // Ausgabe: 2.300000 
113.
    printf("%c\n",cmax('C','B')); // Ausgabe: C 
114.
    out << f; // Schreibt Inhalt von f in Datei 
115.
	out.close(); 
116.
	in >> g; // Liest Datei in g ein 
117.
	in.close(); 
118.
	g.CString_Print(); // Ausgabe: Noch ein Text 
119.
	getchar(); 
120.
	return 0; 
121.
}
6.Anhang – Ein Überladungstest

Um zu testen, ob das Überladen auch mit C eigenen Funktionen
klappt, überladen wir jetzt einfach mal printf. Printf gibt einen
int-Wert zurück und erwartet als Parameter einen String und
optional eine oder mehrere Variablen:

printf("Hallo");
printf("%c %d, Variable_Typ_Character, Variable_Typ_Int);

Wir hingegen übergeben der überladenen Funktion printf zwei
Fließkommawerte, der Rückgabetyp bleibt gleich,die Implementation
überprüft einfach diese Werte auf Gleichheit.

int printf(double x, double y){
return x==y;
}

Die Anweisung printf("%d", printf(zahl,zahl)); gibt am Bildschirm eine
Null aus bei Ungleichheit, eine Eins bei Gleichheit der Argumente. Klappt also.

So, ich glaub, das Tutorial ist jetzt lang genug, kommen wir jetzt mal langsam
zum Ende. Was ich noch erwähnen möchte, ist die Syntax zur Erstellung der
Ausgabe bzw. Eingabe in Dateien.

Zur Ausgabe in Dateien:

ofstream out("c:\\cstring.txt",ios::out);

Der zweite Parameter, ios::out, erzeugt eine Datei zum Schreiben.

Zur Eingabe aus Dateien:

ifstream in("c:\\cstring.txt",ios::in);

Der zweite Parameter, ios::in, öffnet eine Datei zum Lesen.

Da gibt's, analog zur Funktion fopen(char handle, char Modi), natürlich noch
mehr Argumente.

Zum Operator <<, cout << Variable, existieren noch Konstanten, um die
Ausgabe zu formatieren.

Diese beiden Themen werden vom nächsten Tutorial behandelt.

Grüße
Günni
Mitglied: 65593
26.05.2008 um 22:11 Uhr
Gut erklärt!Aber deb Assembler hätte man deutlicher hervorheben sollen,da diese Funktion für die Operanden(binärcodiert) einen beachtlichen Wert darstellt!
Bitte warten ..
Neuester Wissensbeitrag
Windows 10

Powershell 5 BSOD

(8)

Tipp von agowa338 zum Thema Windows 10 ...

Ähnliche Inhalte
VB for Applications
gelöst VBA: Verständnisfrage bei Funktionen, Rückgabe von Werten (3)

Frage von Aximand zum Thema VB for Applications ...

Python
gelöst Python GUI Button funktionen? (7)

Frage von Scuzzy zum Thema Python ...

Heiß diskutierte Inhalte
Microsoft
Ordner mit LW-Buchstaben versehen und benennen (21)

Frage von Xaero1982 zum Thema Microsoft ...

Netzwerkmanagement
gelöst Anregungen, kleiner Betrieb, IT-Umgebung (18)

Frage von Unwichtig zum Thema Netzwerkmanagement ...

Windows Update
Treiberinstallation durch Windows Update läßt sich nicht verhindern (17)

Frage von liquidbase zum Thema Windows Update ...