Was ist der 'Witz' bei der OOP?

Hallo,

vor vielen Jahren habe ich programmieren gelernt, zuerst PASCAL, dann C, dann mit Teilen aus C++.

Jedenfalls habe ich das Denken in Prozeduren gelernt, und ich schreibe alles, was ich brauche, in C. Mitunter benutze ich auch Klassen für bestimmte Teile eines Programms (der Ordnung halber), und schreibe dazu eine Schnittstelle für die Funktionsaufrufe, um im Rest des Programms keine gemischte Syntax zu haben.

Ich nehme zwar an, daß es bei der OOP um mehr geht als bloß um Ordnung oder Übersichtlichkeit, fürchte aber, ich habe dieses „mehr“ nie verstanden (offengesagt zum Teil aus Aversion, weil ich es immer unangenehm fand, OOP-Quelltext zu lesen, oder mich mit MFC o. ä. zu beschäftigen).

Wer kann mir kurz erklären, wofür die OOP eigentlich wirklich gut ist bzw. warum es sich lohnt, das zu lernen?

Grüße,

I.

Wer kann mir kurz erklären, wofür die OOP eigentlich wirklich
gut ist bzw. warum es sich lohnt, das zu lernen?

http://de.wikipedia.org/wiki/Objektorientierte_Progr…

Hallo,

bei der prozeduralen Programmierung sind die Prozeduren „allwissend“, das heißt, jede Prozedur darf auf alles zugreifen. Das heißt aber auch, bei einer Änderung muss jede Prozedur wenigstens überprüft werden, ob sie betroffen ist. DIe Änderung an einer Prozedur kann damit gewaltige Folgen haben.

Bei der Objektorientierung verteilst du die Verantwortung im System. Jedes Objekt hat sieht nur einen winzigen Ausschnitt des Ganzen. Änderungen, die ein Objekt betreffen, kann man deshalb in diesem Objekt lösen. (Z.B. Datenbank: Ein Objekt weiß, wie es erstellt wird. Kein anderer weiß das sonst. Und keiner will es sonst wissen. Änderungen an der DB werden deshalb nur noch in den Objekten, die daraus erstellt werden geändert.)

Vorteil: Man kann Softwareprojekte leichter ändern, große Teile der Software können wiederverwendet werden, Fehler sind einfacher zu finden.

UND: man kann in einer schönen Programmiersprache, nämlich Java, programmieren!

Gruß

Peter

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Hallo,

Änderungen, die ein Objekt betreffen, kann man
deshalb in diesem Objekt lösen.

Vorteil: Man kann Softwareprojekte leichter ändern, große
Teile der Software können wiederverwendet werden

Soweit zur Theorie :wink:

In der Praxis ist es nach meiner bisherigen Erfahrung in der OOP
so, dass recht umfangreiche Vererbungshierarchien bestehen, also
Klassen mit Unterklassen. Gibt es nun größere Änderungswünsche
müssen dann im schlimmsten Fall alle Klassen der
Vererbungshierarchie angepasst werden. Dabei muss man letzlich auch
wissen, welche Teile der Vaterklasse von den Kindklassen wie
verwendet wird. Kurz, die Vererbung verletzt das Geheimnisprinzip
und macht Softwareänderungen schwierig.

Fehler sind einfacher zu finden

Auch hier habe ich wieder Einwände :wink:

Um die Klassen wiederverwendbar zu machen, kommen
insbesondere in der GUI-Programmierung Beobachter-Muster
zum Einsatz. Damit kann sich grob gesagt jede beliebige
Klasse nach Anmeldung Nachrichten von einer anderen Klasse
senden lassen. Da diese Beziehungen aber erst zur Laufzeit
geknüpft werden, ist es sehr schwierig, das (Fehl-)Verhalten
von Komponenten näher zu untersuchen und die Fehlerquelle
unter allen möglichen Kandidaten auszumachen.

Diese Probleme bestehen in der prozeduralen Programmierung
allerdings auch oder sogar in verschärfter Form, sowie noch
einige andere mehr, siehe z.B. auch die Diskussion des gleichen
Themas in http://www.wer-weiss-was.de/cgi-bin/forum/showarticl…
.

Ich wollte durch die kritischen Untertöne nur anklingen lassen, dass
die OOP kein Allheilmittel für alle Programmierprobleme ist.

Gruß,
-Andreas (Java-/C-/Perl-/Tcl-Programmierer)

Vorteil: Man kann Softwareprojekte leichter ändern, große
Teile der Software können wiederverwendet werden

Soweit zur Theorie :wink:

In der Praxis ist es nach meiner bisherigen Erfahrung in der
OOP
so, dass recht umfangreiche Vererbungshierarchien bestehen,
also
Klassen mit Unterklassen.

Daraus ergibt auch noch ein Performance-Problem:

  1. Beim Erzeugen eines Objekts werden dann zig Funktionen Aufgerufen um das Objekt zu initialisieren. Wenn man Pech hat sind die alle noch in unterschiedlichen Bibliotheken hinterlegt…
  2. Beim Freigeben eines Objekts geschieht das Selbe nochmals.
  3. Eine einfach aussehende Zuweisung:
    Obj1 = Obj2
    löst die selbe Lawine an Aufrufen aus. Am Ende wundert sich dann einer, wieso seine Datenbank unbrauchbar ist.

MfG Peter(TOO)

Hallo Auchfalls,

bei der prozeduralen Programmierung sind die Prozeduren
„allwissend“, das heißt, jede Prozedur darf auf alles
zugreifen. Das heißt aber auch, bei einer Änderung muss jede
Prozedur wenigstens überprüft werden, ob sie betroffen ist.
DIe Änderung an einer Prozedur kann damit gewaltige Folgen
haben.

Das kommt aber sehr auf die Disziplin des Programmieres an.

Bei meinen C-Programmen wird das ganze Problem zuerst einmal in Module zerlegt.
Dann besteht jedes Modul aus der normalen xxx.C- und einer xxx.H-Datei. Alles was von aussen zugänglich ist steht in der xxx.H. Zudem ist alles was nach aussen hin nicht öffentlich sein soll in xxx.C als „static“ declariert.

Leider muss ich gerade ein Projekt bearbeiten, bei welchem man sich nicht an diese Regeln gehalten hat. Da sind einfach irgendwo im Quelltext „extern“-Verweise auf Variablen und Prototypen von Funktinen wild verstreut, wo man etwas gerade benötigte. Bei Modulen mit 4000-Zeilen ist das etwas unübersichtlich…

MfG Peter(TOO)

Hallo,

danke für Eure bisherigen Antworten.

Also während bei „klassischem“ C der Quelltext in Module, einzelne Quelltextdateien, unterteilt werden kann, so daß eine Funktion nur das „sieht“, was in im gleichen Modul steht oder global deklariert und mittels Headerdateien zugänglich gemacht wurde - ist die OOP also eine Art von Ausweitung dieses Prinzips: die Funktion „sieht“ nur das, was in der gleichen Klasse steht oder mittels Vererbung zugänglich gemacht wurde. Also:

Klasse ist wie Modul bzw. Quelltextdatei,

und

include-Mechanismus ist wie Vererbung.

Weiters, man kann mit Moduln und Headerdateien mehr oder weniger diszipliniert umgehen, und wenn diszipliniert, erreicht man dasselbe wie mit der OOP, nämlich abgekapselte (im Modul als „static“ deklarierte) Variablen und Funktionen, und man kann in einem kleinen Bereich Änderungen durchführen, ohne sich um das restliche Programm zu kümmern.

Soweit habe ich es bisher verstanden. Ist das im Grunde schon alles, was die OOP bietet, oder gibt es etwas, das nur mit OOP und anders nicht oder nur schwer geht?

Grüße,

I.

Hallo,

ein Vorteil von OOP ist sicher die Kapselung von Functionen und Daten in ein Object. Das erreicht man natürlich auch durch eine saubere prozedurale Programmierung.

Der nächste Vorteil ist die Vererbung. Als Beispiel dient hier ein Anwendungsfenster. Jedes Fenster hat (bei Windows) rechts oben den Button zum schließen des Fensters. Hierbei ist es egal ob es ein Standardfenster, ein Dialog oder eine Toolbar (im nicht angedockten Zustand) ist. Man könnte hier dreimal die selbe Funktionalität implementieren. Bei OOP erzeugt man sich einen gemeinsamen Vorfahren, der die entsprechenden Methoden zum Schließen des Fensters bietet und auch den Button darstellen kann. Danach leitet man von diesem Vorfahren jeweils ein Object für das Standardfenster, den Dialog und die Toolbar ab und alle drei haben ohne Programmieraufwand die Fähigkeit rechts oben den Schließenbutton darzustellen und kann darauf reagieren. Sagt man sich nun, „ach der rote Schließenbutton gefällt mir nicht mehr!“ geht man in den Quelltext unseres Vorfahrobjects und ändert dort die Farbe. Schwupps alle Schließenbuttons der Fenster haben nun die neue Farbe.

Und noch ein Vorteil bei OOP ist die einfachere zusammenarbeit mehrerer Programmierer an einem Projekt. Jeder bearbeitet die ihm zugewiesenen Objecte und nutzt nur die Schnittstellen der anderen.

Gruß Michi dem noch viele weitere Vorteile einfallen würden, wenn er gerade Zeit dazu hätte.

P.S. Kleine Programme erstelle ich trotzdem oft Prozedural, da zwei drei Prozeduren oder Funktionen schneller getippt sind als erst ein Object zu erstellen.

Hallo,

Weiters, man kann mit Moduln und Headerdateien mehr oder
weniger diszipliniert umgehen, und wenn diszipliniert,
erreicht man dasselbe wie mit der OOP, nämlich abgekapselte
(im Modul als „static“ deklarierte) Variablen und Funktionen,
und man kann in einem kleinen Bereich Änderungen durchführen,
ohne sich um das restliche Programm zu kümmern.

Streng genommen müsstest Du sagen, dass die
Prozeduren (oder Funktionen) in C die „Objekte“
sind. Denn diese sind

  • vollständig gekapselt,
  • erhalten Nachrichten (aktuelle Parameter).

Soweit habe ich es bisher verstanden. Ist das im Grunde schon
alles, was die OOP bietet, oder gibt es etwas, das nur mit OOP
und anders nicht oder nur schwer geht?

„Vererbung“, als „NEU“ ist ein „ALT“, geht so mit
include nicht, höchstens „NEU“ hat ein „ALT“.

Ansonsten kannst Du in C eine Tabelle von Funktions-
zeigern in eine struct packen und diese (Funktionen)
dann „objektorientiert“ aufrufen. Um das aber schmerz-
frei und klar machen zu können, nimmt man aber besser C++,
da ist das schon eingebaut :wink:

Insbesondere die Initialisierung wäre in
C sehr häßlich anzusehen, in C++ geschieht
die Initialisierung der „Funktionszeiger“
(heisst jetzt „Memberfunktionen“) „deskriptiv“
während der Deklaration der Klasse.

Letztlich dient die ganze OOP’erei dazu, seinen
Code klar und übersichtlich zu halten; so daß
dann an Wiederverwendung überhaupt erst zu
denken ist!

Ausser bei Java, da wir OOP derart zum Prinzip
gemacht, dass es hin und wieder schwer fällt,
vor lauter Objekt-Syntax-Zeilenrauschen noch
etwas vom eigentlichen Problem zu erkennen :wink:

Grüße

CMБ

Hallo I.,

danke für Eure bisherigen Antworten.

Also während bei „klassischem“ C der Quelltext in Module,
einzelne Quelltextdateien, unterteilt werden kann, so daß eine
Funktion nur das „sieht“, was in im gleichen Modul steht oder
global deklariert und mittels Headerdateien zugänglich gemacht
wurde - ist die OOP also eine Art von Ausweitung dieses
Prinzips: die Funktion „sieht“ nur das, was in der gleichen
Klasse steht oder mittels Vererbung zugänglich gemacht wurde.
Also:

Du denkst immer noch prozedural und nicht OO :wink:

OO geht im Prinzip von den Variablen aus, welche halt etwas komplexer sind und Objekte genant werden.

Also etwas vereinfacht:

Du deklarierst eine „int“ Variable.
Bei OOP sind nun automatisch alle Operationen welche für dieses Objekt definiert sind mit dieser Variablen verbunden (also in diesem Beispiel „-+/*%“ aber auch Funktionen wie atoi() oder itoa() ).
Du kannst dann statt:

short i;
char *s;

i = atoi(s);

einfach:
i = s;
schreiben. Da atoi() im Objekt hinterlegt ist, kann der Compiler aus den unterschiedlichen Typen automatisch erkennen, welche Funktion zur Konvertierung aufgerufen werden muss.
OK, bei einem int macht das noch keine Vorteile, aber wenn du ein kompliziertes struct hast …

Hinzu kommt, dass man auch die einfachen Operatoren wie z.B. „+“ überladen kann, also als Name für eine eigene Funktion verwenden kann.
Dann geht auch statt
s = strcat(s1,s2);
auch
s = s1 + s2;

Nehmen wir mal die „gebräuchlichen“ imaginären Zahlen als kleines Beispiel:

typedef struct
 {
 float real;
 float imag;
 } imaginär;

Da dieses struct öffentlich zugänglich sein muss, kannst du nicht verhindern, dass ein Programmierer an den beiden Elementen selber rumpfuscht. In OO kannst du die ganze Geschichte kapseln, sodass keiner mehr an real und imag rumpfuschen kann, obwohl jeder ein Object des Typs „imaginär“ erzeugen kann. Zudem ist dann auch im Object abgelegt wie es z.B. ausgedruckt wird.
Somit kannst du jederzeit die Deklaration von float in double ändern. Oder du baust das ganze komplett um und verwendest eine eigene Exponential-Darstellung:

typedef struct
 {
 long long mantisse;
 long long exponent;
 } myfloat

typedef struct
 {
 myfloat real;
 myfloat imag;
 } imaginär;

Für den Anwender des Objekts ist nicht sichbar wie „imaginär“ intern aufgebaut ist.

OK, soweit die Theorie, in der Praxis kann man alle Konzepte misbrauchen !!!
Nur weil eine Sprache ein „goto“ kennt, muss man es ja nicht verwenden.

MfG Peter(TOO)

P.S.
Hallo I.,

Vielleicht solltest du einmal ein kleines C+±Prgramm nehmen und es in C übersetzen. Aus hystorischen Gründen kann das eigentlich jeder C+±Compiler noch heute. Anfangs war C++ als eine Art Präprozessor ausgelegt, welcher C-Code produzierte.

MfG Peter(TOO)