Verletzung von Schnittstellen-Anforderungen: Wie behandeln?



  • pumuckl schrieb:

    class Modul{
          //...
       public:
          void SetSomeParameters();
       protected:
          void Start(){ /*...*/ m_run=true; }
          void Stop() { /*...*/ m_run=flase; }
          //...
       private:
          bool m_run;
    };
    
    template <class ModuleToRun>
    struct ModuleRunner : private ModuleToRun
    {
      ModuleRunner(ModuleToRun const& mtr) : ModuleToRun(mtr) { mtr.Start(); }
      ~ModuleRunner() {mtr.Stop(); }
    };
    

    Das ist eine gute Idee, pumuckl!

    Nur verstehe ich das Beispiel noch nicht ganz: Muss ModuleRunner nicht public von ModuleToRun erben? Und dann hat man das Problem, dass man nur mit einer Kopie von Module arbeitet, statt das Module-Objekt selbst zu starten, oder?



  • Roger Wilco schrieb:

    Nur verstehe ich das Beispiel noch nicht ganz: Muss ModuleRunner nicht public von ModuleToRun erben?

    Nein, warum?

    Und dann hat man das Problem, dass man nur mit einer Kopie von Module arbeitet, statt das Module-Objekt selbst zu starten, oder?

    In dem Beispiel stimmt sowieso etwas nicht: Der Parameter mtr wird an die Basis übergeben (in sie kopiert) und dann gestartet. Damit bleibt das Modul-Objekt in der Basis aber ungestartet. Im Destruktor wird ein Objekt mtr benutzt, welches es an dieser Stelle garnicht gibt, da die Klasse keine Membervariablen hat.

    Das könnte man wie folgt lösen:

    template <class ModuleToRun>
    struct ModuleRunner
    {
      // keine const Referenz mehr, da temporäre Objekte nicht lange genug leben würden
      ModuleRunner(ModuleToRun& mtr) : m_mtr(&mtr) { m_mtr->Start(); }
      ~ModuleRunner() {m_mtr->Stop(); }
    
    private:
      ModuleToRun* m_mtr;
    
      // Hinweis: auch noch eine gute Idee: Kopieren verbieten
    };
    


  • LordJaxom schrieb:

    Das könnte man wie folgt lösen:

    template <class ModuleToRun>
    struct ModuleRunner
    {
      // keine const Referenz mehr, da temporäre Objekte nicht lange genug leben würden
      ModuleRunner(ModuleToRun& mtr) : m_mtr(&mtr) { m_mtr->Start(); }
      ~ModuleRunner() {m_mtr->Stop(); }
    
    private:
      ModuleToRun* m_mtr;
    
      // Hinweis: auch noch eine gute Idee: Kopieren verbieten
    };
    

    Auch das ist irgendwo Käse. Wenn du Kopien vermeiden willst, muss mtr auf den Heap. Dann sollte man wegen Vermeidung von Mißverständnissen auch direkt nen Pointer im Konstruktor angeben. Sonst kommt jemand auf den Gedanken, und erstellt mtr auf dem Stack, mit fatalen Folgen für m_mtr, denn der Zeiger wird dann ungültig...

    Es kommt halt jetzt drauf an. Sind das wirklich Module im Sinne von Plugin? Oder steht zur Compilezeit fest, welche Module mit rein kompiliert werden? Dann kannst du es über Template und Inheritance machen. Wenn noch andere Methoden außer start und stop zur Verfügung stehen, brauchts ne Public inheritance, außer du stellst diese in ModuleRunner selber noch mal zur Verfügung (fänd ich komisch).

    Wenn du dich für den Member entscheidest, musst du dann natürlich auch eine Methode anbieten um auf diesen zugreifen zu können (klar...).
    Und dafür brauchst du kein Template, wenn du Modul von ModulAbstractInterface oder so erben lässt.
    Wenn du templates verwenden willst, lass doch den Parameter für den Konstruktor komplett weg und überlass der Templateklasse das Erstellen und Zerstören des Modul-Members.



  • l'abra d'or schrieb:

    Auch das ist irgendwo Käse. Wenn du Kopien vermeiden willst, muss mtr auf den Heap. Dann sollte man wegen Vermeidung von Mißverständnissen auch direkt nen Pointer im Konstruktor angeben. Sonst kommt jemand auf den Gedanken, und erstellt mtr auf dem Stack, mit fatalen Folgen für m_mtr, denn der Zeiger wird dann ungültig...

    Auch bei einem Zeiger im Konstruktor kann ich die Adresse eines Stack-Objekts übergeben. Was im Übrigen nichtmal schlimm ist, das Objekt muss nur länger leben als der Runner. Käse ists trotzdem, da muss ich Dir recht geben, eben weil die Lebensdauer schlecht kontrollierbar ist.

    Wenn man das Modul absolut nicht als Bestandteil der Klasse (sei es als Member oder Basis) haben möchte, wäre noch ein shared_ptr< Modul > (oder weak) denkbar. Wenn den jemand mit einem Stack-Objekt initialisieren möchte, muss er sich explizit Gedanken über die Lebensdauer machen.



  • LordJaxom schrieb:

    Roger Wilco schrieb:

    Nur verstehe ich das Beispiel noch nicht ganz: Muss ModuleRunner nicht public von ModuleToRun erben?

    Nein, warum?

    Gedankenfehler... 😉

    l'abra d'or schrieb:

    Es kommt halt jetzt drauf an. Sind das wirklich Module im Sinne von Plugin? Oder steht zur Compilezeit fest, welche Module mit rein kompiliert werden?

    Es ist mehr grundsätzlich. Konkret habe ich das z.B. bei einer Timer-Klasse, bei der ich das mehrmalige Starten/Stoppen verhindern möchte und bei Anwendungsmodulen, die bei Programmstart je nach Fall (Aufrufparameter) als Konsolenanwendung oder als Windows-Dienst geladen werden sollen. Dabei möchte ich mich davon freimache, wie (Umgebung) der eigentlich Programmcode läuft. Das sollen die Starter-Klassen machen (Konsole anlegen oder Windows-Dienst-typische Aktionen).



  • Folgender Code läuft bei mir problemlos (VC 6.0).

    Nun wollte ich fragen, ob er überhaupt Standard-konform ist, da ich widersprüchliche Sachen bezüglich virtuelle Member-Funktionen von Template-Klassen gelesen habe. Sind die (rein) virtuelle Funktionen in Template-Klassen gestattet? Es funktioniert, aber ist das nur Zufall bzw. liegt es an der Nicht-Standard-Konformität meiner IDE?

    template<class T>
    class Module{
        public:
            Module(){}
            ~Module(){}
    
        public:
            void Start(){ Thread::Start(&ThreadEntry, this); }
            virtual void Stop() = 0;
    
        protected:
            struct implementation;
            boost::shared_ptr<implementation> m_impl;
    
        private: // Einstiegsfunktion für Thread
            static unsigned int __stdcall ThreadEntry(void* param){
                static_cast<T*>(param)->Run();
                return 0;
            }
    };
    
    template<class TModule>
    struct ModuleRunner{
        ModuleRunner(Module<TModule>& module){ module.Start(); }
        ~ModuleRunner(){ Stop(); }
    
        void Stop(){ module.Stop(); }
    };
    


  • Roger Wilco schrieb:

    Sind die (rein) virtuelle Funktionen in Template-Klassen gestattet?

    Ja. Klassentemplates sind nur Vorlagen für Klassen; wenn du die Templateparameter einsetzt, entstehen daraus ganz normale Klassen.

    Trotzdem rate ich dir davon ab, MSVC++ 6 weiterhin zu verwenden.



  • Nexus schrieb:

    Trotzdem rate ich dir davon ab, MSVC++ 6 weiterhin zu verwenden.

    Ja, ich würde gerne umsteigen, darf es aber (noch) nicht.

    Wenn Du mir Gründe gibst, womit ich meinen Vorgesetzten überzeugen kann, möglichst fix umzusteigen, wäre ich Dir dankbar.

    Er schreibt selber seit 20 Jahren C bzw. C++ im Klassen-C-Stil, kennt und nutzt nicht die Standardbibliothek sondern exzessiv die Assistenten von VC++6.0 und MFC/ATL/COM. VC6.0 reicht ihm vollkommen aus (er nutzt nicht einmal eine neue SDK von MS) und als ich ihm mal eine VS2008-Demo zeigte, musste er nur verbittert feststellen, dass seine Programme mit VS2008 nicht mehr kompilieren und die Assistenten ganz anderen Code erzeugen.

    Wenn ich Probleme habe, sagt er mir, ich muss ja nicht unbedingt alle Sprachfeatures ausreizen, sondern soll es lieber "einfach" und im C-Stil machen.

    Ich muss dazu sagen, dass wir hier mehr technische Software programmieren, die meist als Konsolenanwedung oder Windows-Dienst laufen.



  • Du hast ja bereits einige Gründe genannt (modernes standardkonformes C++, Verwendung der Standardbibliothek), aber wenn dein Vorgesetzter derart stur ist, kann man wohl nicht viel machen.

    Du kannst versuchen, ihm weiszumachen, wie veraltet VC 6 ist, was für Bugs die IDE besitzt, und welche Errungenschaften von schönem C++ einem dabei entgehen. Aber wie gesagt, keine Ahnung, obs hilft... 😉



  • Nexus schrieb:

    Du kannst versuchen, ihm weiszumachen, wie veraltet VC 6 ist, was für Bugs die IDE besitzt, und welche Errungenschaften von schönem C++ einem dabei entgehen. Aber wie gesagt, keine Ahnung, obs hilft... 😉

    Die Kompatibilität zu seinem alten VC6.0-Code ist ihm wichtiger als die Standard-Konformität, da er wie gesagt eh nicht die Standardbibliothek nutzt. Er nutzt lieber MFC/ATL und findet diese "einfacher"...

    Es wäre gut eine Quelle zu haben, wo mal einige Bugs und Verbesserungen aufgezählt werden. Ich weiß ja auch nichts genaues, außer dass VC6.0 nicht Standard-Konform ist.

    Er sieht halt nur das Geld und sieht für sich keinen Vorteil. Ganz im Gegenteil: Für ihn bedeutet es, dass sein Code entweder portiert werden muss oder dass wir zwei IDEs (6.0 + 9.0) parallel haben müssen. Beides ist mit Zeit und Kosten verbunden.

    Was soll ich zu den Argument sagen: "Dann benutze halt MFC, wenn es Probleme mit der Standardbibliothek gibt!" Wie soll ich mit Standard-C++ gegen MFC anstinken, wenn Portabilität keine Bedeutung bei uns hat.

    Wenn ich sage, dass MFC ebenfalls einen ordentlichen Versionssprung gemacht hat, sagt er wieder: "Ach, die blähen das mit unnötigen Ballast auf, um nur was neues verkaufen zu können!"

    Wenn ich sage, dass ab Feb. 2003 keine PSDK von MS VC6.0 mehr unterstützt und alle neuen WinAPI-Funktionen damit nicht nutzbar sind für uns, entgegnet er, dass man alles auch mit der alten SDK (die mitgelieferte bei VC6.0!) und den alten WinAPI-Funktionen machen kann, da die i.d.R. weiterhin unterstützt werden.

    Er kommt halt aus der Assembler und C-Welt und ich finde einfach noch nichts, wo ich sagen kann: Für den Aufwand und das Geld bekommen wir die und die Vorteile.



  • Bei so uneinsichtigen Menschen würde ich mit schon überlegen ob ich dort arbeiten möchte.



  • Sowas nennt man beratungsresistent. Fuer gewoehnlich werden solche Organismen verbrannt. Fire him! Dieser Artikel ist vielleicht recht interessant: http://www.paulgraham.com/icad.html . Im Abschnitt "The Cost of Being Average" wird dargelegt, was es ausmachen kann, sich gegen neue Tools, Sprachen oder Technologien zu straeuben. Auch kann man gerade im Bereich Software nicht stillstehen. In http://www.paulgraham.com/avg.html werden Programmiersprachen verglichen, aber es kann auch allgemeiner fuer Technologien verstanden werden. Ist alles recht Lisplastig, aber ich hoffe das stoert nicht.



  • Wäre interessant herauszufinden ob die alte WinAPI in Vista und dem Kommenden Win7 noch komplett unterstützt wird. Denn spätestens wenn seine 90er-Jahre Programme schlichtweg nichtmehr laufen ist es für ihn an der Zeit sich umzustellen (oder sich auf den Altenteil zurückzuziehen, weil er mit dem Alter scheinbar recht unflexibel geworden ist).



  • Roger Wilco schrieb:

    ...entgegnet er, dass man alles auch mit der alten SDK (die mitgelieferte bei VC6.0!) und den alten WinAPI-Funktionen machen kann, da die i.d.R. weiterhin unterstützt werden.

    Und damit liegt er extrem verkehrt. Er hat wohl nur noch nicht Kunden mit neuen Windowsversionen oder benötigt bestimmte API-Funktionen nicht. Ich kenne solche Probleme, auch wenn mein damaliger Programmierchef dann mit einigen dreckigen Hacks an den Problemen vorbei gearbeitet hat. Interessanterweise sind da wahre Stresssituationen entstanden (Ich hatte den Support recht früh gebeten Vista mit zu testen, doch erst als ein Kunde Probleme hatte wurde dies tatsächlich gemacht).

    Viel Spaß wenn dann "urplötzlich" und "unerwartet" bestimmte - teilweise schon im VC6 als deprecated markierte - API-Funktionen nicht mehr das tun, was sie sollen.



  • pumuckl schrieb:

    Wäre interessant herauszufinden ob die alte WinAPI in Vista und dem Kommenden Win7 noch komplett unterstützt wird.

    Wird sie nicht. Bereits mit Vista (und ich glaube auch XP) gibt es einige API-Befehle die nicht mehr unbedingt laufen (frag mich aber nicht nach den konkreten, ist schon etwas her).



  • Tja, danke für Euren Beistand. Leicht ist es wirklich nicht, aber andererseits: Wie würdet Ihr reagieren, wenn Ihr mit 20 Jahren Programmiererfahrung (und bis jetzt habt Ihr alles mit Euren Mitteln auch wunderbar hinbekommen), dann ein Frischling kommt und nach einem halben Jahr plötzlich alles anders machen möchte?

    Erstmal muss man sich beweisen und aufzeigen, dass die neue Programmiertechnik auch effektiven Code erzeugt. So ein Beweis bleib ich ihm noch schuldig.

    Bis dahin stört er sich an meine C++-Konstrukte und möchte mich zum C-Stil bewegen. "Warum so kompliziert? Mach es doch ganz einfach mit #definies. Das versteht dann auch jeder...! Und nicht so viele '::', da muss man ja mit dem Debugger durch, um das zu verstehen...!"

    Log::CLogFile logFile(fileName, Log::CLogFile::FileSize::MB(5)); // Logfile mit max. 5MB Größe
    
    #define LOG_FILE_NAME _T("Test.log")
    #define LOG_FILE_SIZE 5000000 //ca. 5MB
    //...
    CLogFile logFile(LOG_FILE_NAME, LOG_FILE_SIZE);
    


  • Roger Wilco schrieb:

    Tja, danke für Euren Beistand. Leicht ist es wirklich nicht, aber andererseits: Wie würdet Ihr reagieren, wenn Ihr mit 20 Jahren Programmiererfahrung (und bis jetzt habt Ihr alles mit Euren Mitteln auch wunderbar hinbekommen), dann ein Frischling kommt und nach einem halben Jahr plötzlich alles anders machen möchte?

    Ich würde anfangen mich zu fragen, ob ich mich in den letzten 20 Jahren vielleicht zu sehr auf meinen Lorbeeren ausgeruht habe. Mein ehemaliger Chef war, bevor er letzten Monat mit 61 in den Ruhestand ging, nicht so drauf wie Dein Vorgesetzter 🙂

    Erstmal muss man sich beweisen und aufzeigen, dass die neue Programmiertechnik auch effektiven Code erzeugt. So ein Beweis bleib ich ihm noch schuldig.

    Das wüsste er, wenn er den Anschluß behalten hätte. Wenigstens im Bereich derjenigen Sprachen, die er selbst nutzt.

    Log::CLogFile logFile(fileName, Log::CLogFile::FileSize::MB(5)); // Logfile mit max. 5MB Größe
    

    Dann komm ihm bloß nicht mit sowas: FileSize::MegaByte<5>::value 😃



  • Roger Wilco schrieb:

    ...aber andererseits: Wie würdet Ihr reagieren, wenn Ihr mit 20 Jahren Programmiererfahrung..., dann ein Frischling kommt und nach einem halben Jahr plötzlich alles anders machen möchte?

    Wie wäre es mit folgenden Möglichkeiten:
    a) Feststellen das man etwas aufzuarbeiten hat (Damit hatte aber bereits mein etwa 45jähriger Vorgesetzte Probleme, der hat das lernen imho mit 25 weitgehend aufgegeben).
    b) Als Neuling: Vielleicht nach einer besseren Stelle umsehen.

    cu André


Anmelden zum Antworten