Unterschied zwischen objektorientierter und strukturierter Pogrammierung in C++



  • loks schrieb:

    Strukturierte Begründung schrieb:

    Objektorientiertes C++: So viel return wie möglich,...

    Schwachfug. Sowas führt früher oder später nur zu beschissenem Code. EIN return pro Funktion sollte die Regel sein, mehrere nur eine Ausnahme. VIELE returns in einer Funktion = schlechtes Design. (Ausnahme es ist ein switch wo pro case ein return steht)

    In C++ kannst du doch eh nicht wirkliche den Programm Verlauf bestimmen, da Exceptions von jedem externen Programm-Code aufgerufen werden können oder schreibst du (hoffentlich nicht!!) deine Funktionen immer mit einem try/catch drum rum gewrapt?

    Abgesehen davon, was hat das mit Destruktoren zu tuen? Die retten Dich auch nicht vor schlechtem Code... Beispiel:

    Destruktoren ermöglichen dir hier automatische Ressourcenverwaltung. Aber klar, wenn jemand schlechten Code schreibt dann ist der Code schlecht.



  • Man soll ein großes Projekt auf zwei verschiedene Arten angehen können.

    Möglichkeit 1 (modulare Programmierung)
    Entweder mit der Top_Down Methode, bei der von der konkreten Anwendung, die einem vorschwebt, ausgegangen wird. Man notiert sich zuerst möglichst präzise in Natursprache, was das Programm tun soll. Und dann versucht man, diese Natursprache in die Programmiersprache zu übersetzen. Möglichst Zeile für Zeile. Wenn man feststellt, dass die Programmiersprache für ein Objekt der Natursprache keinen Datentyp zur Verfügung stellt, so erfindet man eine Klasse, deren Datenelemente und Funktionen mit 'einfacheren' Datentypen arbeiten können.
    Wenn auch diese einfacheren Datentypen noch zu komplex sind, modularisiert man weiter. Solange, bis am Ende, 'auf der untersten Ebene', nur noch Klassen übrigbleiben, die in der Tat nur noch int, char usw. als Datenelemente enthalten. Der Ausgangspunkt der Planung ist also das 'fertige' Programm, und es wird immer weiter in kleinere Teileinheiten zerhackt, bis am Ende viele kleine, überschaubare, und einfach implementierbare, MODULE übrigbleiben.
    -> Eine solche Herangehensweise nennt man MODULARE PROGRAMMIERUNG. Wenn dabei auch im Zuge der Vereinfachung des komplexen Endprogrammes Klassen entstehen sollten, so folgt man damit doch nicht einem objektorientierten Programmierparadigma.

    Möglichkeit_2 (objektorientierte Programmierung)
    Alternativ sagt man auch Bottom_Up Methode dazu. Es wird dabei überhaupt nicht von einer konkreten Aufgabenstellung ausgegangen, sonder im Gegenteil - aus den zur Verfügung stehenden 'elementaren' Datentypen (int, char etc.) bastelt man 'auf gut Glück' komplexere Klassen, die ihrerseits diese Datenelemente von 'elementarem' Datentyp enthalten. Weil man noch nicht genau vorhersehen kann, wie eine Funktion konkret mit diesen Daten arbeiten wird, deklariert man die meisten Funktionen, von denen man vorausblickend annimmt, dass sich ihre konkrete Implementierung in einer der abgeleiteten Klassen je nach Aufgabenstellung unterscheiden können wird, als VIRTUAL. Polymorphismus ist das primäre Merkmal einer objektorientierten Herangehensweise an eine Aufgabenstellung. Man behält sich also die konkrete Realisierung von Objekten einer Klasse noch vor. Wenn die Basisklassen klug gewählt werden, gelingt es dann auch auf diese Weise, allmählich das komplexe Programm aus diesen einfacheren Bausteinen zu basteln. Dabei ist es auch von Vorteil, dass man oft bei ähnlichen Aufgabenstellungen bereits einen wiederverwendbaren Grundstock von Klassen zur Verfügung hat, sodass sich auch solche Anwendungen dann viel einfacher und schneller umsetzen lassen -> Und das ist die Zielsetzung bei der OBJEKTORIENTIERTEN Programmierung. Wenn auch die 'fertige' Anwendung am Ende so aussieht, als sei sie klug in viele kleine Teilmodule zerlegt, so ist sie dennoch nicht durch das Befolgen eines modularen Programmierparadigmas entstanden.

    Während man mit der Methode 1) schwerlich damit rechnen können wird, dass die Module in einer anderen Anwendung ohne weiteres wiederverwendbar sein werden, so ist das bei Methode 2) die prinzipielle Absicht.
    Andererseits führt Methode 1) zu einer 'maßgeschneiderten', für diese eine Anwendung idR 'optimierten' Architektur der Anwendung, weil wirklich nur diejenige Funktionalität konkret implementiert wird, die benötigt wird.
    Mit der Methode 2) kann es sehr leicht passieren, dass die Bausteine nicht 100% ig optimal zur Konstruktion einer konkreten Anwendung geeignet sind. (Was man aber in den meisten Fällen trotzdem in Kauf nimmt).

    Nur weil irgendwo mit class Klassen definiert wurden, betreibt man deshalb also noch lange nicht unbedingt objektorientierte Programmierung.
    Umgekehrt ist es ein Irrtum, von Programmiersprachen, die das Wort 'class' überhaupt nicht kennen, anzunehmen, es wäre in solchen Programmiersprachen nicht möglich, 'objektorientiert' zu programmieren (die WinAPI ist ein gutes Beispiel, es gibt Fensterklassen, virtuelle Funktionen werden durch Callback- Funktionen würdig vertreten usw. - d.h. objektorientiert, und das alles, obwohl 'C' nicht einmal das Wort 'class' kennt).

    Objektorientierte und modulare Programmierung können in einer 'fertigen' Anwendung - oberflächlich betrachtet - gar nicht voneinander unterschieden werden. Der Unterschied liegt nur in der Art und Weise, WIE die Anwendung geplant wurde. (Eine strukturierte Programmiersprache verfügt über Anweisungen zur bedingten Ausführung von Codezeilen sowie über Wiederholungsschleifen. Mehr ist dazu nicht nötig. Es gibt wohl einige dutzend 'weithin bekannte' imperative Programmiersprachen, die dem genügen. Wer Lust hat, den gesamten Programmcode in ein einziges Modul zu packen -> Strukturierte Programmierung)



  • Hallo

    Ich finde nicht, daß die Ergebnisse von OO- und modularer Programmierung oberflächlich ununterscheidbar sind.

    Überhaupt:

    Bei der OOP beginnt man damit, sich zu überlegen, welche *Substantive* und welche *Adjektive* in der Problembeschreibung vorkommen.
    Die Substantive modelliert man als Objekte ("wer ?"), die Adjektive als Methoden ("macht was ?").

    Das Ergebnis ist ein *datenorientiertes* Programm, d.h. die Daten (private Daten in den Objekten) bestimmen darüber, was mit ihnen gemacht werden darf
    (welche public-Methoden es gibt).

    Im Gegensatz zu *funktionsorientierten* Programmen, bei denen die Funktionen bestimmen, was sie mit den Daten (die ihnen als Argumenten übergeben werden) machen. So etwas entsteht typischerweise durch Software-Design mit strukturierten Programmiersprachen.

    Auch rein formal ist der Unterschied zwischen einem echten OO-Programm, etwa in Smalltalk, und einem block-strukturiertem Programm, etwa in C, riesig:
    Vergleiche mal einen ST-80-FileOut mit einem C-Quelltext.

    Gruß



  • Vielleicht sollte erst mal jemand überhaupt definieren was mit "objektorientierter Programmierung" gemeint ist 😃



  • halloich schrieb:

    Es geht ja nicht darum, dass es sowas im Struktogramm nicht gibt. Bei nem virtuellen Methoden Aufruf bin ich wieder genau da wo ich die Methode aufgerufen habe, wenn sie beendet wurde. Wenn aber ne Exception geworfen wurde, dann bin ich irgendwo wo die Exception gefangen wird und das kann einige Methoden weiter oben sein. Wenn man es so sieht, dass jede Methode die Exception "verarbeitet" und weiter wirft, dann kann man schon sagen, dass es einigermaßen strukturiert abläuft.

    Nun ja, wenn eine Exception geworfen wird, dann ist man erst mal auch wieder da, "wo die Methode aufgerufen wurde". Kommt also vom Prinzip her erst mal aufs gleiche raus wie wenn du ansonsten halt irgendeinen Fehlerwert per return zurückgeben würdest. Nur mit dem Vorteil, dass du den eigentlichen Programmcode von der Fehlerbehandlung trennen kannst. Die Methode kann diese Exception aber natürlich auch weiter werfen, wie du schon gesagt hast, was aber auch gut so ist, denn es kann ja sein, dass diese Methode diese Exception gar nicht verarbeiten muss. Das ist aber dennoch strukturiert, und in keinsterweise mit nem goto zu vergleichen.
    Tja, und jetzt kommt halt C++ ins Spiel. Und da hast du dann insofern recht, als dass der Exception-Mechanismus in C++ dich zu gar nichts zwingt, d.h. du musst keine Exceptions abfangen (ergo musst du sie auch nicht selbst "weiterwerfen"), was dann tatsächlich bedeutet, dass man "irgendwo weiter unten landen kann". IMHO eine klare Schwäche von C++ gegenüber Sprachen wie z.B. Java.
    Ist aber trotzdem kein Grund, den Excpetion-Mechanismus mit nem goto gleichzusetzen.



  • nep schrieb:

    Tja, und jetzt kommt halt C++ ins Spiel. Und da hast du dann insofern recht, als dass der Exception-Mechanismus in C++ dich zu gar nichts zwingt, d.h. du musst keine Exceptions abfangen (ergo musst du sie auch nicht selbst "weiterwerfen"), was dann tatsächlich bedeutet, dass man "irgendwo weiter unten landen kann". IMHO eine klare Schwäche von C++ gegenüber Sprachen wie z.B. Java.

    In sprachen mit static exception handling, z.B. Java, kommt jetzt halt der Exception-Mechanismus ins Spiel, der dich dazu zwingt jede (checked) Exception abzufangen, selbst wenn du darauf nicht reagieren kannst, sie eigentlich gar nichts mit dir zu tun hat und du sie gar nicht kennen willst. IMO eine klare Schwäche von z.B. Java gegenüber Sprachen wie C++.



  • finix schrieb:

    nep schrieb:

    Tja, und jetzt kommt halt C++ ins Spiel. Und da hast du dann insofern recht, als dass der Exception-Mechanismus in C++ dich zu gar nichts zwingt, d.h. du musst keine Exceptions abfangen (ergo musst du sie auch nicht selbst "weiterwerfen"), was dann tatsächlich bedeutet, dass man "irgendwo weiter unten landen kann". IMHO eine klare Schwäche von C++ gegenüber Sprachen wie z.B. Java.

    In sprachen mit static exception handling, z.B. Java, kommt jetzt halt der Exception-Mechanismus ins Spiel, der dich dazu zwingt jede (checked) Exception abzufangen, selbst wenn du darauf nicht reagieren kannst, sie eigentlich gar nichts mit dir zu tun hat und du sie gar nicht kennen willst. IMO eine klare Schwäche von z.B. Java gegenüber Sprachen wie C++.

    Also, erstens muss man in Java auch nichts fangen. Man kann auch alles ans OS weiterleiten, wie in C++, wenn du meinst, dass das besser ist. Ich versteht auch nicht, wie plötzlich eine "sinnlose" Exception auftreten kann die nichts mit dem Aufrufer zu tun hat.

    public void doSomeSQL(String sql) throws SQLException {
       //DB aufruf und die Exception wird in dieser methode nicht gefangen
    }
    


  • finix schrieb:

    nep schrieb:

    Tja, und jetzt kommt halt C++ ins Spiel. Und da hast du dann insofern recht, als dass der Exception-Mechanismus in C++ dich zu gar nichts zwingt, d.h. du musst keine Exceptions abfangen (ergo musst du sie auch nicht selbst "weiterwerfen"), was dann tatsächlich bedeutet, dass man "irgendwo weiter unten landen kann". IMHO eine klare Schwäche von C++ gegenüber Sprachen wie z.B. Java.

    In sprachen mit static exception handling, z.B. Java, kommt jetzt halt der Exception-Mechanismus ins Spiel, der dich dazu zwingt jede (checked) Exception abzufangen, selbst wenn du darauf nicht reagieren kannst, sie eigentlich gar nichts mit dir zu tun hat und du sie gar nicht kennen willst. IMO eine klare Schwäche von z.B. Java gegenüber Sprachen wie C++.

    Nenn mir bitte ein Beispiel dafür. Wenn man auf Exceptions nicht reagieren soll/kann, dann sind diese ja wohl auch sinnlos. Und wie gesagt, du kannst Exceptions ja auch weiter werfen wenn du nicht selbst in einer Methode darauf reagieren willst. Das geht dann eben soweit, wie bis sie ans OS weitergeleitet werden, was dann auf dasselbe wie bei C++ rausläuft.
    Nur mit dem Unterschied, dass du das eben auch bewusst so im Code verankern musst (mittels throws-Anweisungen), was du in C++ eben nicht musst. Das ist nun mal einfach nicht gut, weswegen der Excpetion-Mechanismus in C++ IMHO dem in anderen Sprachen unterlegen ist.



  • nep schrieb:

    Nenn mir bitte ein Beispiel dafür. Wenn man auf Exceptions nicht reagieren soll/kann, dann sind diese ja wohl auch sinnlos. Und wie gesagt, du kannst Exceptions ja auch weiter werfen wenn du nicht selbst in einer Methode darauf reagieren willst. Das geht dann eben soweit, wie bis sie ans OS weitergeleitet werden, was dann auf dasselbe wie bei C++ rausläuft.
    Nur mit dem Unterschied, dass du das eben auch bewusst so im Code verankern musst (mittels throws-Anweisungen), was du in C++ eben nicht musst. Das ist nun mal einfach nicht gut, weswegen der Excpetion-Mechanismus in C++ IMHO dem in anderen Sprachen unterlegen ist.

    Es gibt halt verschiedene Ansichten was "sinnlos" und "sinnvoll" ist. Ich z.B. empfinde es als nahezu schwachsinnig eine exception nur zu fangen um sie dan direkt weiterzuwerfen, das erzeugt massenhaft quasi sinnfreien Code. Für mich macht es mehr Sinn eine Exception nur an _genau_ der Stelle zu fangen wo ich auch vorhabe sie zu verarbeiten... Aber das ist halt meine Meinung...



  • finix schrieb:

    Vielleicht sollte erst mal jemand überhaupt definieren was mit "objektorientierter Programmierung" gemeint ist 😃

    Nein bitte nicht, sonst endet das in einem 50 Seiten Flamewar 😉



  • loks schrieb:

    nep schrieb:

    Nenn mir bitte ein Beispiel dafür. Wenn man auf Exceptions nicht reagieren soll/kann, dann sind diese ja wohl auch sinnlos. Und wie gesagt, du kannst Exceptions ja auch weiter werfen wenn du nicht selbst in einer Methode darauf reagieren willst. Das geht dann eben soweit, wie bis sie ans OS weitergeleitet werden, was dann auf dasselbe wie bei C++ rausläuft.
    Nur mit dem Unterschied, dass du das eben auch bewusst so im Code verankern musst (mittels throws-Anweisungen), was du in C++ eben nicht musst. Das ist nun mal einfach nicht gut, weswegen der Excpetion-Mechanismus in C++ IMHO dem in anderen Sprachen unterlegen ist.

    Es gibt halt verschiedene Ansichten was "sinnlos" und "sinnvoll" ist. Ich z.B. empfinde es als nahezu schwachsinnig eine exception nur zu fangen um sie dan direkt weiterzuwerfen, das erzeugt massenhaft quasi sinnfreien Code. Für mich macht es mehr Sinn eine Exception nur an _genau_ der Stelle zu fangen wo ich auch vorhabe sie zu verarbeiten... Aber das ist halt meine Meinung...

    Bitte setz dich erst mal mit den betreffenden anderen Sprachen auseinander, bevor du sowas behauptest. Du musst z.B. in Java diese Exceptions auch nicht abfangen, die werden automatisch weitergeworfen.


Anmelden zum Antworten