Beispiel zum Unterschied von Strukturen und Klassen
← Dynamische Objekterzeugung | ● | Beispiel zum Unterschied von C und C++ →
Buch mit ISBN in C:
{
char title[30];
char author[30];
char ISBN[13];
};
Um eine C-Datenstruktur mit Leben zu erwecken, benötigt man immer Funktionen, welche einen Zeiger als Parameter auf ein entsprechendes Buch mitbekommen.
Beispiel anhand der Überprüfung der ISBN Nr.:
Eine ISBN ist korrekt, wenn sie aus 12 Zahlen und einer letzten 13ten Zahl, der sogenannten Prüfzahl, besteht. Die gewichtete Summe aller Zahlen muss durch 11 teilbar sein, d.h.:
{
int i,x;
if (strlen(book->ISBN) != 13)
return(false);
for (x=0, i=0; i<13; i++)
x = x+(i+1)*(book->ISBN[i-1]-'0') % 11;
return(x==0);
}
Was kann nun alles passieren, wenn man obige Funktion verwendet? Alles mögliche:
- Ist ein Buch überhaupt initialisiert worden?
- Und sind die Elemente korrekt initialisiert, hat die ISBN z.B. 13 Ziffern?
C Strukturen können dies nicht garantieren, da sie passiv sind:
Undefiniertes Buch:
checkBookISBN(book) -> ???
Falsch initialisiertes Buch:
checkBookISBN(geb) -> false/true
Richtig initialisiertes Buch:
checkBookISBN(geb) -> true
Unkontrollierter Zugriff:
geb.ISBN_[12]++;
checkBookISBN(geb) -> false
Weiterhin ist neben den Problemen einer inkonsistenten Initialisierung eine dynamische Initialisierung der Titellänge nicht möglich.
Mit Klassen lassen sich obige Probleme der Initialisierung elegant lösen:
{
protected:
char *title_;
char *author_;
char ISBN_[13];
// default constructor
Book(char *title, char *author, char *ISBN)
{
title_= strdup(title);
author_= strdup(author);
if (strlen(ISBN)!=13)
throw std::invalid_argument("received ISBN /wo 13 digits");
ISBN_= strncpy(ISBN_,ISBN,13);
}
// destructor
~Book()
{
free(title_);
free(author_);
}
int checkSum()
{
int i,x;
x=0;
for (i=0; i<12; i++)
x = x+(i+1)*(ISBN_[i-1]-'0') % 11;
return(x);
}
bool checkISBN()
{
int x=checkSum();
if (x==10)
return(ISBN_[12]=='X');
else
return(ISBN_[12]=='0'+x);
}
};
Mit einem undefinierten Buch passiert nun nichts Undefinierbares:
Für ein Buch meldet dessen Member-Function die Korrektheit der ISBN:
geb.checkISBN() -> true
Für ein Buch mit zu kurzer ISBN gibt es eine Exception:
{
Book test("test", "author", "123456789"); -> exception
}
catch(std::exception &e)
{
std::cout << e << std::endl;
}
Unkontrollierter Zugriff ist nicht mehr möglich:
geb.ISBN_[12]++; -> compiler error due to access of protected member variable
C++ Klassen können die Integrität von Daten d.h. ihrer Instanzvariablen (member variables) garantieren, da sie das Prinzip der Datenkapselung berücksichtigen und auf Fehler aktiv mittels Elementfunktionen (member function = method) reagieren können.
Zusätzlich können Klassen natürlich aktiv Ihren Zustand verändern, wie zum Beispiel zur Berechnung einer passenden Prüfziffer:
{
int x=checkSum();
if (x==0) ISBN_[12]='0';
else if (x==1) ISBN_[12]='X';
else ISBN_[12]='0'+11-x;
}
← Dynamische Objekterzeugung | ● | Beispiel zum Unterschied von C und C++ →