C/C++ Programmierung · 14 min read · Oct 10, 2025
C/C++ Schritt-für-Schritt - Seite 13
13. Schritt-für-Schritt C/C++ — C++ Programmierung - OOPs
OOP (Objektorientierte Programmierung) in C++
| | 1. Objektorientiertes Paradigma
- Merkmale einer objektorientierten Sprache
- Objekte
- Klassen
- Datenabstraktion
- Datenkapselung
- Vererbung
- Polymorphismus
- Dynamische Bindung
- Nachrichtenübertragung
- Geschichte von C++
- Klassen und Objekte
- Mitgliedsfunktionen, die außerhalb der Klasse definiert sind
- Array von Objekten
- Objekte als Argumente
- Rückgabe von Objekten aus Funktionen
- Konstruktor
- Destruktoren
- Konstruktorüberladung
- Statische Klassendaten
- Statische Mitgliedsfunktionen
- Freundfunktionen |
1. Objektorientiertes Paradigma
Die Grundidee hinter dem objektorientierten Paradigma besteht darin, Daten und die Funktionen, die auf diesen Daten arbeiten, in einer einzigen Einheit zu kombinieren. Eine solche Einheit wird als Objekt bezeichnet.
Durch diese Methode können wir nicht direkt auf Daten zugreifen. Die Daten sind verborgen, sodass sie vor versehentlicher Änderung geschützt sind. Daten und ihre Funktionen werden als in einer einzigen Entität kapsuliert betrachtet. Datenkapselung und Datenverbergung sind Schlüsselbegriffe in der Beschreibung objektorientierter Sprachen.
Ein C++-Programm besteht typischerweise aus einer Anzahl von Objekten, die miteinander kommunizieren, indem sie die Mitgliedsfunktionen des jeweils anderen aufrufen. Die Organisation eines C++-Programms ist in dieser Abbildung dargestellt.
| |
|
2. Merkmale einer objektorientierten Sprache
Hier sind einige wichtige Elemente objektorientierter Sprachen.
| | - Objekte
- Klassen
- Datenabstraktion
- Datenkapselung
- Vererbung
- Polymorphismus
- Dynamische Bindung
- Nachrichtenübertragung |
| |
Objekte
Ein Objekt ist eine Instanz einer Klasse. Es kombiniert sowohl Daten als auch Mitgliedsfunktionen. Objekte sind die grundlegenden Laufzeiteinheiten in einem objektorientierten System. | | |
Klassen
Eine Vorlage oder ein Entwurf, der die Merkmale eines Objekts definiert und beschreibt, wie das Objekt aussehen und sich verhalten sollte. | | |
Datenabstraktion
Identifizierung der unterscheidenden Merkmale einer Klasse oder eines Objekts, ohne alle Informationen über die Klasse oder das Objekt verarbeiten zu müssen. Wenn Sie eine Klasse erstellen - zum Beispiel eine Gruppe von Navigationsschaltflächen für Tabellen - können Sie sie als eine einzige Einheit verwenden, anstatt die einzelnen Komponenten und deren Interaktionen im Auge zu behalten. | | |
Datenkapselung
Ein Begriff der objektorientierten Programmierung für die Fähigkeit, Informationen über ein Objekt, wie interne Datenstrukturen und Code, zu enthalten und zu verbergen. Kapselung isoliert die interne Komplexität des Betriebs eines Objekts vom Rest der Anwendung. Zum Beispiel, wenn Sie die Caption-Eigenschaft auf einer Befehls-Schaltfläche festlegen, müssen Sie nicht wissen, wie der String gespeichert wird. | | |
Vererbung
Ein Begriff der objektorientierten Programmierung. Die Fähigkeit einer Unterklasse, die Merkmale der Klasse, auf der sie basiert, zu übernehmen. Wenn sich die Merkmale der Elternklasse ändern, erbt die Unterklasse, auf der sie basiert, diese Merkmale.
Um die Eigenschaften der Basisklasse auf die abgeleitete Klasse zu vererben. | | |
Polymorphismus
Ein Begriff der objektorientierten Programmierung. Die Fähigkeit, Methoden mit demselben Namen, aber unterschiedlichem Inhalt für verwandte Klassen zu haben. Das Verfahren, das verwendet wird, wird zur Laufzeit durch die Klasse des Objekts bestimmt. Zum Beispiel könnten verwandte Objekte beide Draw-Methoden haben. Ein Verfahren, das ein solches Objekt als Parameter übergibt, kann die Draw-Methode aufrufen, ohne wissen zu müssen, um welchen Objekttyp es sich bei dem Parameter handelt. | | |
Dynamische Bindung
Dynamisch bezieht sich auf die Verknüpfung eines Verfahrensaufrufs mit dem Code, der als Reaktion auf den Aufruf ausgeführt werden soll. Dynamische Bindung bedeutet, dass der Code, der mit einem bestimmten Verfahrensaufruf verknüpft ist, bis zum Zeitpunkt des Aufrufs zur Laufzeit nicht bekannt ist. Es ist mit Polymorphismus und Vererbung verbunden. Ein Funktionsaufruf, der mit einer polymorphen Referenz verknüpft ist, hängt vom dynamischen Typ dieser Referenz ab. | | |
Nachrichtenübertragung
Ein objektorientiertes Programm besteht aus einer Menge von Objekten, die miteinander kommunizieren. Der Prozess der Programmierung in einer objektorientierten Sprache umfasst daher die folgenden grundlegenden Schritte:
- Erstellen von Klassen, die Objekte und deren Verhalten definieren.
- Erstellen von Objekten aus Klassendefinitionen.
- Etablierung der Kommunikation zwischen Objekten. |
3. Geschichte von C++
| Jahr | Sprache | Entwickelt von | Bemerkungen |
| 1960 | ALGOL | Internationales Komitee | Zu allgemein, Zu abstrakt |
| 1963 | CPL | Universität Cambridge | Schwer zu lernen, Schwierig zu implementieren |
| 1967 | BCPL | Martin Richards | Konnte nur mit spezifischen Problemen umgehen |
| 1970 | B | Ken Thompson
AT & T Bell Labs | Konnte nur mit spezifischen Problemen umgehen | | 1972 | C | Dennis Ritchie
AT & T Bell Labs | Verlor die Allgemeinheit von BCPL und B wurde wiederhergestellt | | Frühe 80er | C++ | Bjarne Stroustrup
AT & T | Führt OOPs ein. |
C++ ist eine objektorientierte Programmiersprache. Ursprünglich “C mit Klassen” genannt, wurde C++ von Bjarne Stroustrup in den AT & T Bell Laboratories in Murry Hill, New Jersey, USA, in den frühen achtziger Jahren entwickelt.
Stroustrup, ein Bewunderer von Simula67 (einer OOP-Sprache) und ein starker Befürworter von C, wollte das Beste aus beiden Sprachen kombinieren und mehr Kraft und Eleganz von C schaffen. Das Ergebnis war C++.
C++ ist eine wahrhaft objektorientierte Sprache. Es muss eine Sammlung von Klassen und Objekten sein.
4. Klassen und Objekte
Eine Klasse ist eine Möglichkeit, die Daten und die zugehörigen Funktionen zusammenzubinden. Sie ermöglicht es, die Daten, falls erforderlich, vor externem Zugriff zu verbergen. Bei der Definition einer Klasse erstellen wir einen neuen abstrakten Datentyp, der wie jeder andere eingebaute Datentyp behandelt werden kann. Im Allgemeinen hat eine Klassenspezifikation zwei Teile:
| | 1. Klassendeklaration
- Klassendefinitionsfunktion |
Die Deklaration spezifiziert den Typ und den Geltungsbereich sowohl der Daten als auch der Mitgliedsfunktionen der Klasse. Während die Definition den ausführbaren Code der Funktion spezifiziert.
Die allgemeine Form einer Klassendeklaration ist:
| | class class_name
{
private:
variable declarations;
function declarations;
public:
variable declarations;
function declarations;
}; |
Die Klassendeklaration ähnelt der Strukturdeklaration. Das Schlüsselwort class gibt an, dass die Daten und Funktionen standardmäßig privat sind. Während das Schlüsselwort struct angibt, dass die Daten und Funktionen standardmäßig öffentlich sind. Die Schlüsselwörter privat und öffentlich sind als Sichtbarkeitslabels bekannt.
| |
|
Hier ist ein Beispiel für eine Klasse zur Implementierung einer Mitarbeiterklasse.
| |
|
Das folgende ist das vollständige Programm der emp-Klasse.
| | // Programm zum Akzeptieren und Anzeigen von Mitarbeiterinformationen
#include
using namespace std;
class emp // Klassendefinition
{
private : // private Daten, Funktionen
int eno;
char name[10];
float sal;
public : // öffentliche Daten, Funktionen
void getdata()
{ cin >> eno >> name >> sal; }
void putdata()
{ cout << eno << name << sal; }
};
int main()
{
emp e;
e.getdata();
e.putdata();
return 0;
} |
5. Mitgliedsfunktionen, die außerhalb der Klasse definiert sind
Es besteht die Möglichkeit, Mitgliedsfunktionen außerhalb der Klasse mit dem Gültigkeitsbereichsauflösungsoperator (::) zu definieren.
| | // Programm zum Akzeptieren und Anzeigen von Mitarbeiterinformationen
#include
using namespace std;
class emp // Klassendefinition
{
private : // private Daten, Funktionen
int eno;
char name[10];
float sal;
public : // öffentliche Daten, Funktionen
void getdata();
void putdata();
};
void emp::getdata()
{ cin >> eno >> name >> sal; }
void emp::putdata()
{ cout << eno << name << sal; }
int main()
{
emp e;
e.getdata();
e.putdata();
return 0;
} |
6. Array von Objekten
Der C++-Compiler unterstützt auch Arrays von Objekten.
Das folgende Beispiel veranschaulicht den Vorteil von Objekten mit Arrays.
| | // Programm zum Akzeptieren und Anzeigen von Mitarbeiterinformationen
#include
using namespace std;
class emp // Klassendefinition
{
private : // private Daten, Funktionen
int eno;
char name[10];
float sal;
public : // öffentliche Daten, Funktionen
void getdata()
{ cin << eno << name << sal; }
void putdata()
{ cout >> eno >> name >> sal; }
};
int main()
{
emp e[10]; // Deklaration des Arrays von Objekten
for(i = 0; i <10; i++) // Zugriff auf die Eigenschaften und Methoden der Objekte
e[i].getdata();
for(i = 0; i< 10; i++)
e[i].putdata();
return 0;
} |
7. Objekte als Argumente
Das Übergeben von Objekten an Funktionen ähnelt dem Übergeben von Strukturen, Arrays an Funktionen. Das folgende Programm demonstriert, wie Objekte an Funktionen übergeben werden.
| | // Programm zum Akzeptieren und Anzeigen von Mitarbeiterinformationen
#include
using namespace std;
class emp // Klassendefinition
{
private : // private Daten, Funktionen
int eno;
char name[10];
float sal;
public : // öffentliche Daten, Funktionen
void getdata()
{ cin >> eno >> name >> sal; }
void putdata()
{ cout << eno << name << sal; }
};
void operate(emp t);
int main()
{
emp e;
operate(e);
}
void operate(emp t)
{
t.getdata();
t.putdata();
return 0;
} |
8. Rückgabe von Objekten aus Funktionen
Wir haben gesehen, dass Objekte als Argumente an Funktionen übergeben werden, jetzt werden wir besprechen, wie Objekte aus Funktionen zurückgegeben werden.
| | // Programm zum Akzeptieren und Anzeigen von Mitarbeiterinformationen
#include
using namespace std;
class emp // Klassendefinition
{
private : // private Daten, Funktionen
int eno;
char name[10];
float sal;
public : // öffentliche Daten, Funktionen
void getdata()
{ cin >> eno >> name >> sal; }
void putdata()
{ cout << eno << name << sal; }
};
emp get();
void put(emp t);
int main()
{
emp e;
e = get();
put(e);
return 0;
}
emp get()
{
emp t;
t.getdata();
return t;
}
void put(emp t)
{
t.putdata();
} |
9. Konstruktor
Das folgende Beispiel zeigt zwei Möglichkeiten, Werte für die Datenelemente in einem Objekt zu vergeben. Manchmal ist es jedoch praktisch, wenn ein Objekt sich selbst initialisieren kann, wenn es zum ersten Mal erstellt wird, ohne dass ein separater Aufruf einer Mitgliedsfunktion erforderlich ist.
Die automatische Initialisierung erfolgt durch eine spezielle Mitgliedsfunktion, die als Konstruktor bezeichnet wird. Ein Konstruktor ist eine Mitgliedsfunktion, die automatisch ausgeführt wird, wann immer ein Objekt erstellt wird.
| | // Programm zum Akzeptieren und Anzeigen von Mitarbeiterinformationen mit Konstruktoren
#include
#include
using namespace std;
class emp // Klassendefinition
{
private : // private Daten, Funktionen
int eno;
char name[10];
float sal;
public : // öffentliche Daten, Funktionen
emp() { ; } // Konstruktor ohne Argumente
emp(int teno, char tname[10], float tsal) // Konstruktor mit Argumenten
{
eno = teno;
strcpy(name, tname);
sal = tsal;
}
void getdata()
{ cin >> eno >> name >> sal; }
void putdata()
{ cout << eno << name << sal << endl; }
};
int main()
{
emp e1(1001, “Magic”, 6700.45);
emp e2;
e2.getdata();
e1.putdata();
e2.putdata();
return 0;
} |
Das obige Beispielprogramm akzeptiert Werte auf zwei Arten, einmal mit Konstruktoren und einmal mit Mitgliedsfunktionen. Ein Objekt wird, wann immer es deklariert wird, automatisch mit den gegebenen Werten unter Verwendung von Konstruktoren initialisiert. Während das Objekt e2 nur über seine Mitgliedsfunktion zugänglich ist.
Ein weiteres Beispiel zur Unterscheidung der Verwendung des Konstruktors.
| | // Objekte repräsentieren eine Zählervariable
#include
using namespace std;
class counter
{
private :
int count; // Variable count
pubilc :
counter() { count = 0; } // Konstruktor
void inc_count() { count++; } // Zähler erhöhen
int get_count() { return count; } // Zähler zurückgeben
};
int main()
{
counter c1, c2; // definieren und initialisieren
cout << “\nC1 = “ << c1.get_count(); // anzeigen
cout << “\nC2 = “ << c2.get_count();
c1.inc_count(); // c1 erhöhen
c2.inc_count(); // c2 erhöhen
c2.inc_count(); // c2 erhöhen
cout << “\nC1 = “ << c1.get_count(); // erneut anzeigen
cout << “\nC2 = “ << c2.get_count();
return 0;
} |
| | Ein Konstruktor hat die folgenden Eigenschaften.
- Automatische Initialisierung
- Rückgabewerte wurden nicht akzeptiert
- Gleicher Name wie die Klasse
- Formatierung durcheinanderbringen |
10. Destruktoren
Ein Destruktor hat denselben Namen wie der Konstruktor (der derselbe wie der Klassenname ist), wird jedoch von einer Tilde vorangestellt:
| | // Demonstration eines Destruktors
#include
using namespace std;
class temp
{
private :
int data;
public :
temp() { data = 0; } // Konstruktor (gleicher Name wie Klasse)
~temp() { } // Destruktor (gleicher Name mit Tilde)
}
int main()
{
temp t;
return 0;
} |
11. Konstruktorüberladung
Die Fähigkeit, Funktionen mit demselben Namen, aber unterschiedlichem Inhalt für verwandte Klassen zu haben. Das Verfahren, das verwendet wird, wird zur Laufzeit durch die Klasse des Objekts bestimmt.
| | // Demonstration einer Konstruktorüberladung
#include
using namespace std;
class ttime
{
private :
int hh, mm, ss;
public :
ttime() {hh = 0; mm = 0; ss = 0; } // Konstruktor mit Initialisierung
ttime(int h, int m, int s) // Konstruktor mit 3 Argumenten
{
hh = h; mm = m ; ss = s;
}
ttime(int h, int m) // Konstruktor mit 2 Argumenten
{
hh = h; mm = m; ss = 0;
}
ttime(int h) // Konstruktor mit 1 Argument
{
hh = h; mm = 0; ss = 0;
}
~ttime() { }
void get_time()
{
cin >> hh >> mm >> ss;
}
void put_time()
{
cout << endl << hh << “ “ << mm <<” “ << ss;
}
};
int main()
{
ttime t1, t2(12, 12, 12), t3(4, 5), t4(11); // Konstruktoren aufrufen
t1.get_time();
t1.put_time();
t2.put_time();
t3.put_time();
t4.put_time();
return 0;
} |
12. Statische Klassendaten
Wenn ein Datenelement in einer Klasse als statisch definiert ist, wird nur ein solches Element für die gesamte Klasse erstellt, egal wie viele Objekte es gibt. Ein statisches Datenelement ist nützlich, wenn alle Objekte derselben Klasse ein gemeinsames Informationsitem teilen müssen. Eine Mitgliedsvariable, die als statisch definiert ist, hat ähnliche Eigenschaften wie eine normale statische Variable: Sie ist nur innerhalb der Klasse sichtbar, aber ihre Lebensdauer ist das gesamte Programm.
| | // Demonstration von statischen Daten
#include
using namespace std;
class temp
{
private :
static int count; // Nur ein Datenelement für alle Objekte
public :
temp() { count++; } // Zähler erhöhen, wenn Objekt erstellt
int getcount() { return count; } // Zähler zurückgeben
};
int main()
{
temp t1, t2, t3; // drei Objekte erstellen
cout << “\nCount ist “ << t1.getcount( ); // jedes Objekt
cout << “\nCount ist “ << t2.getcount( ); // sieht denselben
cout << “\nCount ist “ << t3.getcount( ); // Wert von count
return 0;
} | | | Die Ausgabe des obigen Programms ist wie folgt: (wenn es immer noch statisch ist)
Count ist 3
Count ist 3
Count ist 3
Die Ausgabe des obigen Programms (wenn es automatisch ist)
Count ist 1
Count ist 1
Count ist 1 |
13. Statische Mitgliedsfunktionen
Wie statische Mitgliedsvariablen können wir auch statische Mitgliedsfunktionen haben. Eine Mitgliedsfunktion, die als statisch deklariert ist, hat die folgenden Eigenschaften.
| | - Eine statische Funktion kann nur auf andere statische Mitglieder (Funktionen oder Variablen), die in derselben Klasse deklariert sind, zugreifen.
- Eine statische Mitgliedsfunktion kann mit dem Klassennamen (anstatt ihrer Objekte) wie folgt aufgerufen werden:
class-name :: function-name;
|
| | // Programm zur Demonstration einer statischen Mitgliedsfunktion
#include
using namespace std;
class test
{
int code ;
static int count; // statische Mitgliedsvariable
public:
void setcode() { code = ++count; }
void showcode() { cout << “Objekt Nummer :” << code << endl; }
static void showcount() // statische Mitgliedsfunktion
{
cout << “Count :” << count << endl;
}
};
int test :: count;
int main()
{
test t1, t2;
t1.setcode();
t2.setcode();
test::showcount(); // Zugriff auf statische Funktion
test t3;
t3.setcode();
test::showcount();
t1.showcode();
t2.showcode();
t3.showcode();
return 0;
} |
14. Freundfunktionen
| |
|
Private Mitglieder können nicht von außerhalb der Klasse zugegriffen werden. Das heißt, eine Nicht-Mitgliedsfunktion kann keinen Zugriff auf die privaten Daten einer Klasse haben. Es könnte jedoch eine Situation geben, in der wir möchten, dass zwei Klassen eine bestimmte Funktion teilen. Dies wird einfach durch Freund-Funktionen erreicht.
| | Eine Freundfunktion besitzt bestimmte besondere Eigenschaften: - Sie befindet sich nicht im Geltungsbereich der Klasse, für die sie als freundlich deklariert wurde.
- Da sie sich nicht im Geltungsbereich der Klasse befindet, kann sie nicht mit dem Objekt der Klasse aufgerufen werden. Sie kann wie eine normale Funktion ohne Hilfe eines Objekts aufgerufen werden.
- Im Gegensatz zu Mitgliedsfunktionen kann sie nicht direkt auf die Mitgliedsnamen zugreifen und muss einen Objektnamen und den Punkt-Zugriffsoperator mit jedem Mitgliedsnamen verwenden.
- Sie kann entweder im öffentlichen oder im privaten Teil einer Klasse deklariert werden, ohne ihre Bedeutung zu beeinflussen.
- Normalerweise hat sie die Objekte als Argumente. |
| | // Programm zur Demonstration einer Freundfunktion
#include
using namespace std;
class test
{
int a;
int b;
public:
void setvalue() { a = 25; b = 40; }
friend float sum(test s); // FREUND deklariert
};
float sum(test s)
{
return float (s.a + s.b ) / 2.0; // s.a & s.b sind die privaten Mitglieder
// der Klasse test, aber sie waren zugänglich
// durch die Freundfunktion
}
int main()
{
test x;
x.setvalue();
cout << “Mittelwert = “ << sum(x) << endl;
return 0;
} |
Ein weiteres Beispiel zur Implementierung einer Freundfunktion als Brücke zwischen zwei Klassen.
Das folgende Programm erstellt zwei Objekte von zwei Klassen und eine Funktion, die beiden Klassen freundlich ist.
In diesem Beispiel kann die Freundfunktion auf die Datenmitglieder beider Klassen zugreifen und den größten Wert beider Klassen-Datenmitglieder berechnen.
| | #include
using namespace std;
class second;
class first
{
int a;
public:
first(int temp) { a = temp; }
friend void max(first, second);
};
class second
{
int b;
public:
second(int temp) { b = temp; }
friend void max(first, second);
};
void max(first f, second s)
{
if ( f.a > s.b ) // beide Datenmitglieder von first, second können
cout << “Max “<< f.a; // über die Freundfunktion max aufgerufen werden
else
cout << “Max “<< s.b;
}
int main()
{
first f(20);
second s(30);
max(f, s);
return 0;
} |
Ref: Objektorientierte Programmierung in Turbo C++: Robert Lafore
Erhalte neue Beiträge in deinem Posteingang.
Kein Spam. Jederzeit abmelden.