Gruselige Programmierbeispiele auf Wikipedia



  • Wenn irgendein Konzept anhand eines Beispiels demonstriert wird, geht das bei Wikipedia selten gut aus.

    Aggregation:

    class Ehe // Beispiel einer Aggregation.
    {
    private:
        Person& _partner1; // Enthaltener Teil.
        Person& _partner2; // Enthaltener Teil.
        Ehe ()             // Versteckter Konstruktor.
        {   throw new ArgumentException ("Die Ehe muss mit den Ehepartnern initialisiert werden.");
        }
    public:
        // Initialisierender Konstruktor.
        Ehe (Person& partner1, Person& partner2)
        {   _partner1 = partner1;
            _partner2 = partner2;
        }
    };
    

    Was gar nicht geht:
    * Unterstrich am Anfang eines Bezeichners
    * unnötiger private Konstruktor
    * Initialisierungslisten fehlen in beiden Konstruktoren, sodass man das nicht einmal kompilieren kann

    • throw new ? Java-geschädigt oder was?
    • ArgumentException ähem

    Was mich noch stört:
    * bescheuerte Kommentare
    * seltsame Formatierung

    • private vor public

    Das zweite Beispiel ist noch schöner:

    class Gebäude // Beispiel einer Komposition.
    {
    private:
        Stockwerk* _stockwerke; // Enthaltene Teile.
        Gebäude ()              // Versteckter Konstruktor.
        {   throw new ArgumentException ("Das Gebäude muss mit der Anzahl Sockwerke initialisiert werden.");
        }
    public:
        // Initialisierender Konstruktor.
        Gebäude (int anzahlStockwerke)
        {   if (anzahlStockwerke < 1)
                throw new ArgumentException ("Das Gebäude muss mindestens 1 Stockwerk haben.");
            _stockwerke = new Stockwerk[anzahlStockwerke];
            for (int indexStockwerk = 0; indexStockwerk < anzahlStockwerke; indexStockwerk++)
                _stockwerke[indexStockwerk] = new Stockwerk(indexStockwerk + 1);
        }
        // Destruktor zur expliziten Zerstörung der Stockwerke.
        virtual ~Gebäude ()
        {
            for (int indexStockwerk = sizeof (_stockwerke) / sizeof (void*); indexStockwerk > 0; indexStockwerk--)
                delete _stockwerke[indexStockwerk - 1];
            delete[] _stockwerke;
        }
    };
    

    Schlimm:
    * Umlaut in Bezeichner
    * sinnloser Standardkonstruktor
    * wieder die seltsame Ausnahme

    • int statt size_t
    • new[] !
      * keine Ausnahmebehandlung
      * Schwachsinn, der von der Aussage ablenkt
    • virtual Destruktor, so etwas gibt es doch in Java gar nicht (?)
    • sizeof 😞

    Suboptimal:
    * fehlende Blockklammern bei for (ja, auch Anfänger dürfen sich die angewöhnen)
    * Postfix ++

    Außerdem fehlt explicit auch hier.

    for (int indexStockwerk = sizeof (_stockwerke) / sizeof (void*); indexStockwerk > 0; indexStockwerk--)
    

    sizeof (_stockwerke) / sizeof (_stockwerke) hätte wohl irgendwie falsch ausgesehen.
    Hallo? Nicht einmal die Grundlagen von C++ beherrschen, aber die Objekte in der richtigen Reihenfolge zerstören...



  • TyRoXx schrieb:

    Was gar nicht geht:
    * Unterstrich am Anfang eines Bezeichners

    Das ist innerhalb von Klassen erlaubt.

    TyRoXx schrieb:

    Was mich noch stört:

    • private vor public

    Find ich ok aber ist vielleicht Geschmacksache.

    Dem Rest kann ich zustimmen.





  • Noch etwas einzuwenden?

    class Ehe // Beispiel einer Aggregation.
    {
    private:
        Person& _partner1; // Enthaltener Teil.
        Person& _partner2; // Enthaltener Teil.
    public:
        // Initialisierender Konstruktor.
        Ehe(Person& partner1, Person& partner2)
    		: _partner1(partner1)
    		, _partner2(partner2)
        {
        }
    };
    
    #include <vector>
    #include <cassert>
    
    class Gebaeude // Beispiel einer Komposition.
    {
    private:
        std::vector<Stockwerk> _stockwerke; // Enthaltene Teile.
    public:
        // Initialisierender Konstruktor.
        explicit Gebaeude(size_t anzahlStockwerke)
        {   
    		assert((anzahlStockwerke >= 1) && "Das Gebäude muss mindestens 1 Stockwerk haben.");
    		_stockwerke.reserve(anzahlStockwerke);
            for (size_t indexStockwerk = 0; indexStockwerk < anzahlStockwerke; ++indexStockwerk)
    		{
                _stockwerke.push_back(Stockwerk(indexStockwerk + 1));
    		}
        }
    };
    

    Edit:

    • explicit entfernt


  • Habs mal ausgebessert, wird aber nicht angezeigt?

    Edit: Jap, etwas einzuwenden, und zwar explicit bei 2 Construktorparametern.



  • TyRoXx schrieb:

    Was gar nicht geht:
    * Unterstrich am Anfang eines Bezeichners
    * unnötiger private Konstruktor
    * Initialisierungslisten fehlen in beiden Konstruktoren, sodass man das nicht einmal kompilieren kann

    • throw new ? Java-geschädigt oder was?
    • ArgumentException ähem

    Was mich noch stört:
    * bescheuerte Kommentare
    * seltsame Formatierung

    • private vor public

    Das stört dich daran? Wirklich?
    Die komplette Idee eine Ehe so zu modellieren ist Schwachfug.

    Für eine Erklärung reicht es aber. Es soll ja nicht C++ erklären...

    Das 2. Beispiel ist zB garkeine Erklärung von Aggregation sondern von Speicherverwaltung :p



  • Ethon schrieb:

    Habs mal ausgebessert, wird aber nicht angezeigt?

    Muss wohl erst jemand freigeben. Ich habe mich zurückgehalten, um nicht voreilig eine halbgare Korrektur vorzunehmen.

    Ethon schrieb:

    Edit: Jap, etwas einzuwenden, und zwar explicit bei 2 Construktorparametern.

    Habe ich mir so angewöhnt, falls ich mal die Parameteranzahl auf 1 ändere und explicit vergesse. Aber in diesem Beispiel ist es wirklich unnötig.

    Warum verwendest du logic_error und nicht assert ?



  • Korrekt wäre invalid_argument, stimmt. 😉
    Ich benutze die std-Exceptions meistens so dass ich system_error verwende wenn ein System-API Call versemmelt wird, runtime_error wenn etwas anderes fehlschlägt und logic_error, wenn eine Funktion mit unsinnigen Parametern gefüttert wird. Natürlich wäre ein assert schlauer, aber dann wäre im Release der Deppenschutz weg, deswegen nehm ich assert nur, wenn kein Nutzer direkt damit arbeitet.



  • Shade Of Mine schrieb:

    Die komplette Idee eine Ehe so zu modellieren ist Schwachfug.

    Warum denn das?



  • TyRoXx schrieb:

    Shade Of Mine schrieb:

    Die komplette Idee eine Ehe so zu modellieren ist Schwachfug.

    Warum denn das?

    Warum denn schon?
    Eine Ehe ist eine Beziehung zwischen 2 Leuten, in diesem Fall kennen sich die Partner nichtmal...

    Fangen wir lieber mal an: was findest du an dieser Lösung denn gut?



  • TyRoXx schrieb:

    Was gar nicht geht:
    * Unterstrich am Anfang eines Bezeichners

    Das mache ich immer so, und fast alle, die ich kenne ebenfalls. Unterstriche am Anfang sind bei Instanzvariablen überhaupt kein Problem.

    Die Beispiele bei Wikipedia sind vielleicht nicht perfekt und nicht mal schön, aber ich hab mich noch nie daran gestört, weil ich meist auf den ersten Blick erkenne, was sie zeigen/verdeutlichen sollten und damit haben sie ihren Zweck 100% erfüllt und dann interessieren mich irgendwelche Kleinigkeiten überhaupt nicht mehr.



  • TyRoXx schrieb:

    Noch etwas einzuwenden?

    #include <vector>
    #include <cassert>
    
    class Gebaeude // Beispiel einer Komposition.
    {
    private:
        std::vector<Stockwerk> _stockwerke; // Enthaltene Teile.
    public:
        // Initialisierender Konstruktor.
        explicit Gebaeude(size_t anzahlStockwerke)
        {   
    		assert((anzahlStockwerke >= 1) && "Das Gebäude muss mindestens 1 Stockwerk haben.");
    		_stockwerke.reserve(anzahlStockwerke);
            for (size_t indexStockwerk = 0; indexStockwerk < anzahlStockwerke; ++indexStockwerk)
    		{
                _stockwerke.push_back(Stockwerk(indexStockwerk + 1));
    		}
        }
    };
    

    Ja. Ich würde alles wegmachen, was nicht nötig ist.
    Also assert weg. Der Test mag zwar hübsch sein, aber ist hier mehr Ballast, als daß es was brächte.

    Ebenso explicit.

    Und reserve.

    Und die Laufvariable würde ich nur i nennen. Und von 1 solange <=anzahlStockwerke laufen lassen.

    Und die Kommentare einheitlich alle drüber oder besser alle rechte dran.



  • explicit gehört zu so einem Konstruktor.

    #include <vector>
    
    // Beispiel einer Komposition.
    class Gebaeude
    {
    private:
    	// Enthaltene Teile.
        std::vector<Stockwerk> _stockwerke;
    public:
        // Initialisierender Konstruktor.
        explicit Gebaeude(size_t anzahlStockwerke)
        {  
            for (size_t i = 1; i <= anzahlStockwerke; ++i)
            {
                _stockwerke.push_back(Stockwerk(i));
            }
        }
    };
    


  • TyRoXx schrieb:

    Noch etwas einzuwenden?
    (...)

    Ja, die unnötigen {} beim for , das geht gar nicht!



  • TyRoXx schrieb:

    explicit gehört zu so einem Konstruktor.

    explicit gehört für mich vor jeden Ctor, egal wie viel Parameter er nimmt.
    (Und das meine ich ernst)



  • hustbaer schrieb:

    explicit gehört für mich vor jeden Ctor, egal wie viel Parameter er nimmt.

    Koenntest du bitte kurz erklaren warum? Bei einem Parameter ist es mir klar sowie bei Konstruktoren mit mehreren Parametern mit Default-Values. Aber warum immer?



  • u.A. deswegen:

    // Version 1
    class Foo
    {
    public:
        Foo(int shoeSize, int legCount);
    };
    

    Commit: "added default value (most people have 2 legs)"

    // Version 1
    class Foo
    {
    public:
        Foo(int shoeSize, int legCount = 2);
    };
    

    BAM

    Und weil es schöner "aligned" wenn man mehrere Konstuktoren hat 🙂

    EDIT: Tippfehler korrigiert 🙂



  • hustbaer schrieb:

    Und weil es schöner "aligned" wenn man mehrere Konstuktoren hat 🙂

    #define constructor explicit
    

    So, jetzt aligned es noch viel hübscher.

    class Foe
    {
    public:
        constructor Foe(int showSize, int legCount);
        constructor Foe(Foo theOtherFoe);
    };
    


  • In der objektorientierten Programmierung ist die Aggregation eine besondere Art der Assoziation zwischen Objekten. Sie beschreibt eine stärkere Beziehung zwischen Objekten als die allgemeine Assoziation - denn bei der Aggregation sind die assoziierten Objekte nicht mehr gleichwertig, sondern ein Objekt „ist Teil von“ einem anderen Objekt. Im Gegensatz zur Komposition (die auch eine „ist Teil von“ Assoziation beschreibt) kann das Teil-Objekt ohne das Aggregat-Objekt existieren. In der UML wird die Aggregation durch eine leere Raute, die Komposition durch eine ausgefüllte Raute symbolisiert.

    Findet ihr den Text dazu nicht auch schlecht? Wenn man da nicht weiß, was Aggregation ist, weiß man es nachher auch nicht.



  • nochwas schrieb:

    ...

    Findet ihr den Text dazu nicht auch schlecht? Wenn man da nicht weiß, was Aggregation ist, weiß man es nachher auch nicht.

    Das ist das Problem mit UML. Man versucht es intuitiv auf eine konkrete Programmiersprache abzubilden und eckt dabei ständig an.


Anmelden zum Antworten