Wieviel Performance kostet die Objekt orientierte Programmierung?



  • @Herausforderer
    Und was erwartest du von dem Code? Da kann man vielleicht 3 Klassen einbauen:
    - Random generator
    - Ship
    - Field
    Wobei aber keine interessanten Eigenschaften oder sonst etwas vorhanden sind. Die Random Generator Klasse funktioniert genau so wie deine jetzige Funktion. Die Schiff Klasse ist ja nichts anderes als eine Größenangabe und Field bleibt ein Wrapper um std::vector, mit Konstruktor und shoot Methode.

    Klar, das sieht dann alles etwas schöner aus. Aber um ernsthaft einen Vorteil aus der Objektorientierung zu bekommen ist das Programm viel zu unkomplex. Die Random Funktion packst du in die Generator-Klasse. Ship hält einfach eine Größenangabe. Die placeShips Funktion wird zum Field Konstruktor und Teil deines Hauptloops wird halt zu Field::shootOn(unsigned Position);
    Du siehst also, abgesehen davon dass man hier eh vor allem die Performance von rand() misst, wird da genau das gleiche Ergebnis rauskommen.



  • Objektorientiert programmieren bedeutet ja nicht, nur ein paar Getter und Setter für meine Arrays zu machen, sondern ein Klassendesign mit Kapselung zu haben und OO Pattern zu verwenden, also z.B. Observer für Schuss-Events oder ähnliches verwenden.

    So wie ich es gemacht habe ist doch garnichts objektorientiert und gekapselt. Bei einem OO Design macht man doch nicht ein paar Zahlen in ein Spielfeld-Array um die Positionen der Schiffe zu speichern. Bei einem OO Design würde man doch wohl eher sowas machen, dass das Schiff seine Größe und Position kenn und weiß wo es getroffen wurde. Überlegt euch einfach mal, wie ihr sowas objektorientiert designen würdet, ohne an meinen Code zu denken.

    Das rand() möglicherweise am meisten Zeit brauchen könnte, habe ich auch schon befürchtet, aber dann kann man ja ein schnelleres rand verwenden.



  • Herausforderer schrieb:

    Das rand() möglicherweise am meisten Zeit brauchen könnte, habe ich auch schon befürchtet, aber dann kann man ja ein schnelleres rand verwenden.

    Das geht erstaunlicherweise noch, es braucht "nur" 50% der Zeit.

    Und nein, objektorientiert zu programmieren bedeutet nicht, irgendwelche Pattern von Wikipedia zu kopieren und zur Lösung eines nicht existenten Problems einzusetzen. Wenn die Schiffe irgendwie selbstständig wären, agieren könnten, eventuell eine KI bräuchten, verschiedene Eigenschaften etc. hätten, dann würde es langsam spannend. So ist es einfach nur ein gepunktetes Feld, in diesem Sinne ist auch dein Code bereits Objektorientiert, du hast nur kein class um dein Feld und freie Funktionen statt Methoden. Aber dein Feld ist trotzdem ein Objekt - und deine Funktionen können auf diesem agieren. Ha! Da musst du dich schon mehr anstrengen, um der Objektorientierung zu entkommen. :xmas1:

    Und genau deshalb macht deine Frage so wenig Sinn. Objektorientierung ist halt erst mal nur eine Sichtweise, das beschreibt keinen konkreten Implementierungsweg. Wenn du meckern willst, dann nenne irgendein Konzept das du für sinnlos erklärst. 😉



  • OOP & Performance schrieb:

    Wieviel Performance kostet die Objekt orientierte Programmierung?

    Wie volkard schon gesagt hat, hängt das von der Sprache bzw. ganz konkret vom jeweiligen Compiler ab. Objektorientierung ist etwas für den Programmierer und nicht für den Prozessor. Der Compiler kann daraus machen, was er will. Wie viel von der Objektorientierung im kompilierten Programm noch zu erkennen ist, ist nicht festgelegt.

    Abgesehen davon geht es bei der Objektorientierung nicht um Performance, sondern darum, dass komplexer Code beherrschbar und wartbar bleiben soll. Wie gesagt: Es ist eine Sache für den Programmierer. Wenn Du die Vorteile von OOP testen möchtest, dann musst Du ein größeres Programm (einige 10.000 Zeilen) einmal objektorientiert und einmal rein prozedural, programmieren. Und dann musst Du Vergleichen, wie hoch der Zeitbedarf beim Programmieren war, wie viele Fehler noch drin sind, wie gut Du den Code jeweils lesen kannst und so weiter.

    Performance ist eine Frage von ganz kleinen Codebereichen in einem Programm. Jeder kennt die 90-10 Regel "90% der Zeit wird in 10% des Codes verbracht". Wobei das vermutlich eher eine 97-3 Regel ist. Wenn man ein Performanceproblem hat, dann schaut man sich ganz genau die kleinen Codebereiche an, die dafür verantwortlich sind. Und dann kann man sich immer noch überlegen, ob in dem Zusammenhang irgendein objektorientiertes Konstrukt der Übeltäter ist und man diesen kleinen Codebereich bezüglich Performance optimieren sollte.



  • cooky451 schrieb:

    So ist es einfach nur ein gepunktetes Feld, in diesem Sinne ist auch dein Code bereits Objektorientiert, du hast nur kein class um dein Feld und freie Funktionen statt Methoden. Aber dein Feld ist trotzdem ein Objekt - und deine Funktionen können auf diesem agieren. Ha! Da musst du dich schon mehr anstrengen, um der Objektorientierung zu entkommen. :xmas1:

    Wenn du so objektorientiert programmierst, dann programmierst du nicht objektorientiert. Das ist nicht nur ein gepunktetes Feld. Gerade vorher wolltest du noch zwei Klassen Field und Ship machen. Jetzt willst du praktisch nur noch eine Klasse Game machen und alles in diese werfen.

    Wenn du meckern willst, dann nenne irgendein Konzept das du für sinnlos erklärst. 😉

    Ich will nicht meckern. Ich würde nie ein größeres Projekt nicht objektorientiert machen, aber ich glaube schon, dass objektorientierte Programme meistens langsamer sind, weil man anders designt, dafür aber meistens auch flexibler ist.


  • Mod

    314159265358979 schrieb:

    Objektorientierung kostet grundsätzlich gar nichts.

    Quark, mal wieder, leider. Aber nicht so großer Quark wie von dem Herausforderer, der mit allen Mitteln versucht, sich seine Welt so zu verbiegen, wie es ihm passt.

    Es kann technische Nachteile geben bei dem Code der von typischen objektorientierten Ansätzen erzeugt wird.



  • Eins euro fufzik



  • SeppJ schrieb:

    314159265358979 schrieb:

    Objektorientierung kostet grundsätzlich gar nichts.

    Quark, mal wieder, leider. Aber nicht so großer Quark wie von dem Herausforderer, der mit allen Mitteln versucht, sich seine Welt so zu verbiegen, wie es ihm passt.

    Es kann technische Nachteile geben bei dem Code der von typischen objektorientierten Ansätzen erzeugt wird.

    Des Herausforderers "nicht objektorientierte" Version dürfte als einzigen Schwachpunkt haben, den der optimierende Compiler nicht sieht, daß der vector dauernd neu angelegt und gelöscht wird. Also ausgerechnet sein Versuch, doch ein wenig OO zu programmieren.



  • SeppJ schrieb:

    314159265358979 schrieb:

    Objektorientierung kostet grundsätzlich gar nichts.

    Quark, mal wieder, leider.

    cooky451 schrieb:

    Objektorientierung ist halt erst mal nur eine Sichtweise, das beschreibt keinen konkreten Implementierungsweg. Wenn du meckern willst, dann nenne irgendein Konzept das du für sinnlos erklärst. 😉

    Und genau deshalb ist dein Post Quark, SeppJ, und nicht meiner.



  • Wenn ich nur von einer Sichtweise spreche, kann ich aber auch nicht von Performance sprechen.
    Ich muss von einer Implementierung sprechen, um über Performance zu diskutieren - und dann kostet OOP unter Umständen (richtig, Programmierung. Nicht Analyse, nicht Design. Programmierung).

    Absolute statements...:)



  • volkard schrieb:

    SeppJ schrieb:

    314159265358979 schrieb:

    Objektorientierung kostet grundsätzlich gar nichts.

    Quark, mal wieder, leider. Aber nicht so großer Quark wie von dem Herausforderer, der mit allen Mitteln versucht, sich seine Welt so zu verbiegen, wie es ihm passt.

    Es kann technische Nachteile geben bei dem Code der von typischen objektorientierten Ansätzen erzeugt wird.

    Des Herausforderers "nicht objektorientierte" Version dürfte als einzigen Schwachpunkt haben, den der optimierende Compiler nicht sieht, daß der vector dauernd neu angelegt und gelöscht wird. Also ausgerechnet sein Versuch, doch ein wenig OO zu programmieren.

    Das Erstellen und Füllen des vectors kann man aus der Schleife raus nehmen, am Ende ist der vector sowieso wieder so gefüllt wie am Anfang. Bringt aber nur so ca. 7%.

    Wenn ihr meint, dass meine Version objektorientiert ist, wie sieht dann eine nicht objektorientierte Version aus?



  • Herausforderer schrieb:

    Wenn ihr meint, dass meine Version objektorientiert ist, wie sieht dann eine nicht objektorientierte Version aus?

    Genau so. Es ist eine verdammte Sichtweise!! 😃



  • [quote="cooky451"]

    OOP & Performance schrieb:

    Wieso kostet es in C++ nichts?

    Weil aus

    class A
    {
      float value_;
    public:
      A(float value)
        : value_(value)
      {}
      float &value()
      {
        return value_;
      }
    };
    
    int main()
    {
      A a(534.65f);
      std::cout << a.value();
      getchar();
    }
    

    das da wird:

    012D14A0  fld         dword ptr [__real@4405a99a (12EA0D8h)]  
    012D14A6  push        ecx  
    012D14A7  fstp        dword ptr [esp]  
    012D14AA  call        std::basic_ostream<char,std::char_traits<char> >::operator<< (12D1550h)
    

    [QUOTE]

    Damit ist die Datenkapselung aber fürn Arsch:

    #include <iostream>
    #include <stdio.h>
    
    class A
    {
      float value_;
    public:
    
      A(float value)
        : value_(value)
      {}
    
      float &value()
      {
        return value_;
      }
    };
    
    int main()
    {
      A a(534.65f);
      std::cout << a.value();
      float* d = &a.value(); // Oh je...
      *d = 10; // Damit ist die Datenkapselung fürn Arsch
      std::cout << std::endl << *d;
      std::cout << std::endl << a.value(); // LOL
      getchar();
    }
    

    Zudem solltest du mal beschreiben, was genau du mit Objektorientierung meinst. Ist FILE* aus C eine Klasse? Was schlägst du als Alternative vor?

    Die Datenkapselung und das Geheimnisprinzip sollte schon aufrecht erhalten bleiben.
    OOP heißt, daß eine andere Person die Implementierung der Objektdaten und Objektmethoden nicht kennen muß, alles was er kennen darf, sind die Deklarationen der public Methoden und public Objektvariablen.
    Also die Schnittstellen zu dem Objekt.

    D.h. also, wenn er seinen Code so wie hier bei

    float* d = &a.value();
    

    programmiert, dann fliegt der Code mächtig auf die Schnauze, wenn die Klasse intern irgendwann während der Softwareentwicklung verändert wird.

    Deswegen gibt es das Prinzip der Datenkapselung und dem Geheimnisprinzip, sowie der maximalen Entkopplung.

    Dein Code ist also zwar vielleicht schnell, aber er erfüllt die Bedingungen der OOP nicht mehr.
    Da kann man das ganze Klassenkonstrukt auch gleich weglassen.



  • Dann gleich noch eine Frage.

    Wieso heftest du den Adressoperator an den Funktionsnamen und nicht an den Rückgabetyp, so wie es IMO sein sollte?

    cooky451 schrieb:

    float &value()



  • Hehe jo, du hast in völlig zusammenhangslosem Beispielcode einen imaginären Schönheitsfehler gefunden. 👍
    Dass der resultierende Binärcode völlig identisch mit der "nicht Referenz"-Version bleibt, dürfte wohl klar sein.

    Pfusch schrieb:

    Wieso heftest du den Adressoperator an den Funktionsnamen und nicht an den Rückgabetyp, so wie es IMO sein sollte?

    Deswegen: http://ideone.com/NGNYG
    Ich würde Referenzen und Pointer auch lieber dem Datentypen zuschreiben. Das Komitee selbst scheint sich ja nicht mal ganz einig über die Schreibweise zu sein. Früher standen */& beim Variablennamen, jetzt stehen sie öfter beim Typ. Einheitlich machen sie es jedenfalls nicht, von daher zählt für mich vor allem die Eigenschaft von oben.



  • cooky451 schrieb:

    Hehe jo, du hast in völlig zusammenhangslosem Beispielcode einen imaginären Schönheitsfehler gefunden. 👍

    kleine schönheitsfehler, wenn man jenen überhaupt so nennen will, find ich super 👍



  • cooky451 schrieb:

    Hehe jo, du hast in völlig zusammenhangslosem Beispielcode einen imaginären Schönheitsfehler gefunden. 👍

    Der Fehler ist weder ein Schönheitsfehler noch imaginär oder sonstwas.

    Eine mutable Referenz auf ein Member zurückzugeben macht effektiv die Kapselung kaputt. Das Ding erst private zu machen, und dann einen "Referenz-Getter/Setter" anzubieten, halte ich für äusserst albern. Das ist bloss Vorspiegelung falscher Tatsachen.

    Erst Recht in dem Zusammenhang in dem du es gebracht hast: wenn es keine echte Kapselung in dem Code gibt, wie soll er dann als Beispiel dafür dienen, dass Kapselung nix kostet?



  • Welche Tatsachen? Die Klasse heißt A und die einzige Membervariable "value_", es existiert einfach kein Umfeld. Ist std::vector jetzt auch schlecht gekapselt? Das Beispiel sollte nur verdeutlichen, dass Methode sowie Referenz wegoptimiert werden, und das hat es auch geleistet. Dass ohne Referenz nicht plötzlich weniger optimiert wird ist doch klar.



  • cooky451 schrieb:

    Welche Tatsachen? Die Klasse heißt A und die einzige Membervariable "value_", es existiert einfach kein Umfeld.

    Die (falsche) Tatsache "hier ist was gekapselt".

    Ein Member einer Klasse das "private" ist, impliziert, dass es nicht uneingeschränkt von ausserhalb verwendbar ist -- wieso sollte man es sonst "private" machen und nicht gleich "public"?
    Sobald du eine mutable Referenz zurückgibst, ist das aber nicht mehr der Fall, denn dann ist das "private" Member auf einmal uneingeschränkt von ausserhalb verwendbar.

    Ergo: der Kuchen ist eine Lüge.

    Ist std::vector jetzt auch schlecht gekapselt?

    Nein. Bietet denn std::vector Referenzen auf seine Member der über Referenz-Getter an? Nein, tut er nicht. Sonst könnte man vec.size() = 42; oder ähnlich gefährlichen Unsinn schreiben.

    Das Beispiel sollte nur verdeutlichen, dass Methode sowie Referenz wegoptimiert werden, und das hat es auch geleistet. Dass ohne Referenz nicht plötzlich weniger optimiert wird ist doch klar.

    Ein Beispiel das man in Gedanken erstmal abändern muss, und dann Vermutungen darüber anstellen ob die abgeänderte Version sich auch noch so verhält wie die gezeigte, ist irgendwie kein gutes Beispiel.



  • hustbaer schrieb:

    Ergo: der Kuchen ist eine Lüge.

    Ne, es gibt nämlich keinen Kuchen. Der einzige Sinn der Funktion war ja, dass sie wegoptimiert wird.

    hustbaer schrieb:

    Nein. Bietet denn std::vector Referenzen auf seine Member der über Referenz-Getter an? Nein, tut er nicht.

    operator [] ?

    hustbaer schrieb:

    Ein Beispiel das man in Gedanken erstmal abändern muss, und dann Vermutungen darüber anstellen ob die abgeänderte Version sich auch noch so verhält wie die gezeigte, ist irgendwie kein gutes Beispiel.

    So und hier kommen wir wohl zum einzig relevanten Teil der Diskussion. Und nein, ich denke das Beispiel war gut, weil es zeigt, dass Zugriffe über Methoden auch dann komplett wegopimiert werden, wenn man mit non-const Referenzen arbeitet. (Was z.B. beim std::vector nicht ganz unwichtig ist.)


Anmelden zum Antworten