Große Verständnisprobleme beim ersten größeren C++-Projekt



  • Es wäre echt schön, wenn mir jemand helfen könnte, da ich meine Arbeit bald abgeben muss 😮



  • Das Singleton müsste OK sein solange du nicht aus mehreren Threads "getInstance" aufrufst, und solange das "Verwaltung vs. Abschlussarbeit" ein Schlampigkeitsfehler in deinem Posting war.
    EDIT: "müsste" heisst: kommt drauf an wo du's verwendest. Guckst du da:

    http://www.parashift.com/c++-faq-lite/ctors.html ([10.14])

    /EDIT

    Das andere geht so (bloss ein unsinniges Beispiel um die Syntax zu zeigen):

    class foo
    {
    public:
        foo(int a, int b, int c)
            : m_a(a), m_b(b), m_c(c)
        {}
    
    private:
        int m_a;
        int m_b;
        int m_c;
    };
    
    class bar
    {
    public:
        bar(int x);
    
    private:
        const foo m_foo; // muss natürlich nicht const sein, kann aber
    };
    
    // in bar.cpp:
    
    static int compute_c(int x)
    {
       // ...
       return 123;
    }
    
    bar::bar(int x)
        : m_foo(x, 666, compute_c(x))
    {
    }
    

    Nennt sich "initializer-list".



  • Wow, vielen Dank!! Damit ist mir auf jeden Fall geholfen und ja es war ein Tippfehler...

    Noch eine Frage: Ich beschäftige mich schon länger mit der Informatik und der Programmierung und immer wieder taucht in Beispielen die Variable foo auf. Was ist denn die Geschichte dahinter??





  • static Abschlussarbeit* getInstance();
    
    Verwaltung* Verwaltung::getInstance() 
    {
    	static Verwaltung instance;
    	return &instance;
    }
    

    Ist das so korrekt gelöst??

    Jein.

    "static" in der KLassendeklaration meint Klassenmethode bzw Variable.
    "static" in einer Methode meint "Initialisierung genau beim ersten Durchlauf".

    Das Singletonmuster sieht in C++ eigentlich etwas anders aus:

    // Verwaltung.hpp
    class Verwaltung
    {
    
        public:
            static Verwaltung* getInstance();
        /*
         * ...
         */ 
        protected:
        // für Kindklassen; sonst auch privat !
            Verwaltung(); 
            virtual ~Verwaltung();    
        /*
         * ...
         */ 
        private:
            static Verwaltung* _pInstance;  
        /*
         * ...
         */ 
    
    };
    // EOF Verwaltung.hpp
    
    // Verwaltung.cpp
    #include "Verwaltung.hpp"
    
    Verwaltung* Verwaltung::_pInstance = (Verwaltung*)NULL; // Wichtig; sonst linkt es nicht  
    
    Verwaltung* getInstance()
    {
        if ( NULL == _pInstance )
        {
            _pInstance = new Verwaltung();
        } 
        return _pInstance;
    
    };
    
    Verwaltung(){}; 
    ~Verwaltung(){};
    
    // EOF Verwaltung.cpp
    

    So wird _pInstance in einem bestimmten Speicherbereich (meist "Heap" genannt) angelegt. Und kann auch von einem "friend" ( bei private ) oder auch einer Kindklasse ( bei protected ) ggf zum Programmende wieder zu einem definierten Zeitpunkt destruiert werden - aber von niemand anderem wg. des protected oder private.

    Wo eine lokaler "static" Variable liegt wissen Götter und Compiler-Entwickler.
    Sowas kann Probleme machen!
    Wann ( und ggf sogar ob - da bin ich mir nicht sicher obs im Standard garantiert wird ) die Variable auch wieder destruiert wird laesst sich kaum steuern.

    Wenn ich jetzt in verschiedenen Klassen jeweils Verwaltung::getInstance() aufrufe bekomme ich dann immer dieselbe Instanz/Objekt?? Das ist ja der eigentliche Sinn der ganzen Geschichte...

    Jein.

    Innerhalb einer Instanz des Codes ja - also innerhalb eines Programms oder eines statisch gelinkten Bibliothek.
    Bei einer DLL sieht das _GANZ_ aus. Da müsste getInstance() mehr leisten.

    Dann tritt insgesamt noch die Frage auf ob Das Programm mehrere Threads unterscheidet.

    Dann müssen _ALLE_ Funktionen mit Zugriff auf ein gemeinsames Objekt mittels Mutex / Semaphore / Critical / Section / Event geschützt werden, wenn aus auch eine schreibende Funktion gibt.
    Also nicht Zugriff auf "normale" automatische lokale Variablen,

    void foo() 
    {
        int i; // also sowas  
    }
    

    wohl aber KLassen- und Instanzvariablen und statische Variablen in Funktionen...

    Gint es Nebenläufigkeit (aka. "Multithreading") in dem Projekt ?

    Grüsse

    Gast++



  • Streiche:

    Verwaltung* getInstance()
    {
        if ( NULL == _pInstance )
        {
            _pInstance = new Verwaltung();
        } 
        return _pInstance;
    
    };
    
    Verwaltung(){}; 
    ~Verwaltung(){};
    

    Setze:

    Verwaltung* Verwaltung::getInstance()
    {
        if ( NULL == _pInstance )
        {
            _pInstance = new Verwaltung();
        } 
        return _pInstance;
    
    };
    
    Verwaltung::Verwaltung(){}; 
    Verwaltung::~Verwaltung(){};
    

    Vielleicht sollte ich doch besser in ner IDE schreiben...
    😉



  • Danke für die ausführliche Antwort!!

    Mmh, leider gibt es Multithreading in meinem Projekt...
    Ich hab gelesen, dass ich auch noch den Kopierkonstruktor der Verwaltung beim Entwurfsmuster Singleton vor einem öffentlichen Zugriff schützen muss. Das wurde bislang nicht erwähnt. Soll es trotzdem gemacht werden?

    Danke für deine Hinweise. Das werde ich direkt heute abend mal durchdenken und ausprobieren...



  • Dr.Ottel schrieb:

    Ich hab gelesen, dass ich auch noch den Kopierkonstruktor der Verwaltung beim Entwurfsmuster Singleton vor einem öffentlichen Zugriff schützen muss.

    Ups, jetzt hast Du mich aber erwischt!

    Ich sollte _wirklich_ lieber echtes Beispiel in den Editor laden und kopieren...

    Dr.Ottel schrieb:

    Das wurde bislang nicht erwähnt. Soll es trotzdem gemacht werden?

    Ja, unbedingt!
    Und gleich auch noch den Zuweisungsoperator.
    Beide private deklarieren.

    Dr.Ottel schrieb:

    Danke für deine Hinweise. Das werde ich direkt heute abend mal durchdenken und ausprobieren...

    Dr.Ottel schrieb:

    Danke für die ausführliche Antwort!!
    Mmh, leider gibt es Multithreading in meinem Projekt...

    Dann hast Du unter C++ aber _wirklich_ eine Aufgabe vor Dir!

    1. Gefährdete Variablen sollten nie nach aussen gereicht werden, also nie einen Pointer oder eine Referenz auf ein Member zurückgeben.

    2. Klassen- und Instanzvariablen sind eh nie public. Punkt.

    3. "static" in Funktionen ist ekelhaft. Bin bislang immer ( 10 Jahre lang ) gut ohne das ausgekommen.

    4. 5 Philosphen sitzen an einem runden Tisch beim chinesischen Abendessen. Zwischen Tellern in dem Rund liegt jeweils genau ein Chop-Stick.
      Jeder braucht zwei Chop-Sticks zum Essen.
      Jeder greift zum Stick zu seiner Rechten und wartet auf den Linken.
      => Alle bleiben hungrig !

    Das nennt man einen "Deadlock" - zwei Threads haben jeweils ein notwendiges Synchronisationsobjekt (SO, also Mutes et al.) locked und warten jeweils gegenseitig darauf dass der jeweils andere das jeweils andere Synchronisationsobjekt freigibt.

    So bewegt sich nichts mehr!

    => Möglichst nie einen zweiten exklusiven Zugriff für einen Ablauf anfordern.
    Das erste zunächst wieder freigeben.

    1. "Wenn zwei sich streiten freut sich der Dritte": oder
      "Kann man eine Konkurrenz nicht dialogisch klären, braucht es einen Moderator"

    Das gilt für (C++)Klassen und Threads genauso.

    1. Queues und asynchrone ("You called me? - call later or I'll call you back!") Schnittstellen sind hilfreich.

    2. Die STL ist nicht threadsicher.

    Viel mehr als dies und ein Buch "Pham/Garg : Multithreaded Programming with Win32" hatte ich auch nicht bei meinem ersten nebenläufigen Systemkonzept.

    Good Luck

    *this



  • Hallo zusammen,

    eigentlich will ich hier ja nicht als Grünschnabel dazwischenquatschen (es ist faszinierend, den großen Jungs bei der Arbeit zuzuhören 🙂 ), aber mir brennt da eine Frage auf der Zunge.

    viande schrieb:

    class KuenstlicheIntelligenz
    {
        Verwaltung* verwaltung;
        int some_member;
        
    public:
        KuenstlicheIntelligenz(Verwaltung* __verwaltung)
        : verwaltung(__verwaltung)
        { }
        
        virtual void denken() = 0;
    };
    

    http://www.c-plusplus.net/forum/viewtopic-var-t-is-39461.html In diesem Thread steht etwas über die (Nicht)Verwendung von Unterstrichen (besonders von doppelten) - ist das in diesem Beispiel also Absicht? Soll das so sein oder ist es einfach nur Zufall und egal?

    Vielen Dank schonmal im Voraus!



  • Nope, ist sicher nicht Absicht sondern Unwissenheit.
    (das mit den doppelten Underscores)



  • Dr.Ottel schrieb:

    Danke für die ausführliche Antwort!!

    Mmh, leider gibt es Multithreading in meinem Projekt...
    Ich hab gelesen, dass ich auch noch den Kopierkonstruktor der Verwaltung beim Entwurfsmuster Singleton vor einem öffentlichen Zugriff schützen muss. Das wurde bislang nicht erwähnt. Soll es trotzdem gemacht werden?

    Danke für deine Hinweise. Das werde ich direkt heute abend mal durchdenken und ausprobieren...

    Du solltest dir mal Loki angucken. Dort gibt es eine Multithreading-fähige Implementation des Singleton-Musters. Das kann sogar noch einiges mehr. Aber dazu sollte man vielleicht das Buch dazu gelesen haben.
    Siehe hier: http://sourceforge.net/projects/loki-lib/



  • Noch eine dumme Frage:

    Welche Sichtbarkeit hat eigentlich die main-Methode??
    Also mit welcher Sichtbarkeit versehe ich sie innerhalb eines UML-Diagramms?
    Ich tippe mal auf static!?

    Und noch ne kleine Frage:
    get- und set-Methoden kann man doch aus einem UML-Diagramm rauslassen, oder?
    Ich tippe mal auf ja!?



  • Dr.Ottel schrieb:

    Noch eine dumme Frage:

    Welche Sichtbarkeit hat eigentlich die main-Methode??
    Also mit welcher Sichtbarkeit versehe ich sie innerhalb eines UML-Diagramms?
    Ich tippe mal auf static!?

    😉
    Die ist nur unter Java eine Methode.

    In C++ ist das eine freie Funkion aka UML "Class Utility".
    "Sichtbarkeit" würde ich als "Implementation" deklarieren; schliesslich "sieht" die erst der Linker.

    Dr.Ottel schrieb:

    Und noch ne kleine Frage:
    get- und set-Methoden kann man doch aus einem UML-Diagramm rauslassen, oder?
    Ich tippe mal auf ja!?

    Soll generiert oder nur dokumentiert werden?
    Um welches Werkzeug geht's denn?

    Grüsse

    *this



  • Naja, wenn dein main inetwa so aussheit, dann kannst du es wohl ganz weglassen:

    int main()
    {
       try
       {
          MyApp app;
          return app.run();
       }
       catch (std::exception const& e)
       {
          ReportFatalError(e);
          return 1;
       }
    }
    


  • Danke für die schnellen Antworten.
    Also es soll nur dokumentiert werden und von daher lasse ich mal die get- und set-Methoden weg, da es sonst zu unübersichtlich werden würde.

    Das mit der main-Methode überrascht mich aber...
    Man lernt halt nie aus!!



  • Dr.Ottel schrieb:

    Danke für die schnellen Antworten.
    Also es soll nur dokumentiert werden und von daher lasse ich mal die get- und set-Methoden weg, da es sonst zu unübersichtlich werden würde.

    Kleine Anmerkung dazu:

    Wenn es öffentliche get und set Methoden zu einer realen Variable gibt ist die Damit so gut wie öffenlich.
    Einzig mögliches Konkurrenzhandling wäre dann och ein Plus.

    Dr.Ottel schrieb:

    Das mit der main-Methode überrascht mich aber...
    Man lernt halt nie aus!!



  • Wenn man ein getX() und ein setX() hat, kann man dann nicht einfach ein Attribut "x (get/set)" schreiben?
    EDIT: das mit der main Funktion ist bloss meine Meinung, ich habe mit UML nicht soviel um die Ohren, kann nicht sagen ob das "böse" wäre. Bloss ich würde die main Funktion nicht dokumentieren - macht halt IMHO keinen Sinn, da die sowieso sogut wie leer sein sollte /EDIT



  • hustbaer schrieb:

    Wenn man ein getX() und ein setX() hat, kann man dann nicht einfach ein Attribut "x (get/set)" schreiben?

    Das ist genau das Problem damit.

    Deshalb hat es mich immer gewundert dass alte Rose-Versionen genau das standardmässig mitgenerieren
    ( ja, Leute, ich weiss dass man das ausschalten kann )

    Es macht schcn nocht einen Unterschied public : getX/setX u. private : X statt "public : X" zu verwenden. In nebenläufigen Umgebungen man kann für die Accessor-Funktionen z.B. Critical Sections schaffen.

    Allerdings wäre ein solche Lösung sehr aufwendig wenn es sich um viele Attribute handelt.

    Gegen getX/setX mit einem "virtuellen" Attribut, also einem Attribut das eienn komplexen Instanzstatus representiert gibt's natürlich keine Einwände.

    Das ist auch genau das Verfahren das z.B. ATL/COM und CORBA bei IDL-Attributen verwenden.
    Da _kann_ es zu getX/setX auch ein X member geben; meistens ist dies aber nicht der Fall.

    Beispiel:

    #import <msxml6.dll>
    
    //...
    IXMLDOMParseError2Ptr pError = pXMLDoc->validate();
    MSXML2::IXMLDOMParseErrorCollectionPtr pErrs = pError->allErrors;
    
    /*
     * Der Insterface-Pointer der da raus kommt kann gar kein member sein,
     * weil das ggf. nicht mit dem OLE-Threading-Modell konsistent wäre.
     */
    

    Grüsse

    Gast++



  • Gast++, ich verstehe nicht worum es dir geht.

    Ein Attribut in einem UML Diagramm muss doch nicht einer Variable im C++ Programm entsprechen?!?
    Also wenn ich UML nur zu Designzwecken bzw. zur Dokumentation hernehme, dann nehme ich mir auch die Freiheit die "Attribute" so zu implementieren wie es richtig und nötig ist. Was meistens NICHT eine public Variable sein wird. Trotzdem kann ich im UML einfach ein Attribut "x" einzeichnen - einfach weils kürzer und übersichtlicher ist.

    Die ganzen get/set Methoden ganz wegzulassen finde ich auf jeden Fall schlimmer, denn dann weiss man überhauptnichtmehr was es für Attribute gibt.



  • hustbaer schrieb:

    Gast++, ich verstehe nicht worum es dir geht.

    Es geht darum, nicht die Kapselung von private: A.x durch public ( m.E. auch pretected ) get_x/set_x Methden aufzuweichen.

    hustbaer schrieb:

    Ein Attribut in einem UML Diagramm muss doch nicht einer Variable im C++ Programm entsprechen?!?

    Das ist aber die Standardimplementierung eines Attributs.

    hustbaer schrieb:

    Also wenn ich UML nur zu Designzwecken bzw. zur Dokumentation hernehme, dann nehme ich mir auch die Freiheit die "Attribute" so zu implementieren wie es richtig und nötig ist. Was meistens NICHT eine public Variable sein wird. Trotzdem kann ich im UML einfach ein Attribut "x" einzeichnen - einfach weils kürzer und übersichtlicher ist.

    Das ist glaube ich alles davon abhängig für wen die Doku geschrieben wird.
    Wenn's für die Implementierer geschrieben wird muss die intene Struktur offengelgt werden.
    Für Verwender der Klasse muss dies nicht erfolgen

    hustbaer schrieb:

    Die ganzen get/set Methoden

    Braucht man denn wirklich so viele davon?

    Grüsse

    Gast++


Anmelden zum Antworten