Frage zu Vererbung



  • Hallo,
    angenommen, ich habe eine solche Klasse:

    class SettingsController
    {
    public:
        virtual SettingsCamera *foo() const
        {
               // default behaviour
        }
    };
    

    Anschließend mache ich eine MockUp-Klasse davon:

    class SettingsControllerMockup : public SettingsController
    {
    public:
        virtual SettingsCamera *foo() const override
        {  
               return m_cameraSettings;
        }
    
        void setFoo(SettingsCamera *cameraSettings)
        {  
               set m_cameraSettings = cameraSettings;
        }
    };
    

    Angenommen, die abstrakte Klasse wird irgendwo im Code benutzt:

    
    void bla()
    {
          SettingsControllerMockup instance;
          doSomething(instance);
    }
    
    void doSomething(SettingsController &settinginstance)
    {
          // foo von der Basisklasse wird aufgerufen anstatt von SettingsControllerMockup  :-(
          SettingsCamera *cameraSettings = settinginstance.foo();
    }
    

    Dann wird leider der Code der Basisklasse aufgerufen anstatt der geerbten Klasse. Kann ich das irgendwie umgehen?

    Danke im Voraus!
    Steffo



  • @Steffo sagte in Frage zu Vererbung:

    // foo von der Basisklasse wird aufgerufen anstatt von SettingsControllerMockup 😞

    Das glaube ich nicht.

    Du verwendest aber auch nicht den gezeigten Code. Der würde nicht übersetzt.



  • @manni66 sagte in Frage zu Vererbung:

    Das glaube ich nicht.

    Ich auch nicht.



  • Hm, ok. Dann eine andere Frage: Können Singletons hier ein Problem sein? Ich habe das Gefühl, als bekomme ich zwei verschiedene Instanzen.

    class SettingsController
    {
    public:
        static SettingsController &instance()
        {
               static SettingsController singleton;
               return singleton;
        }
    }
    

    Verwende ich das dann an einer Stelle:

    void CheckDrawerCommandTest::initTestCase()
    {
        auto settings = static_cast<SettingsControllerMockup&>(SettingsControllerMockup::instance());
        settings.setImageProcessingSettings(&m_settingsImageProcessingDummy);
        settings.setCalibrationSettings(&m_settingsCalibrationDummy);
    }
    

    Dann sind die Instanzen an anderer Stelle zufällgerweise null.



  • @Steffo

    Wo kommt denn Dummy auf einmal her? Egal, ein Singleton, welches du casten musst, sieht jedenfalls erstmal verdächtig aus.
    Mehr kann man aus den Codefetzen aber jetzt auch nicht sagen.

    Ich habe das Gefühl, als bekomme ich zwei verschiedene Instanzen.

    Ja, sicher, sofern du meinst das es eine SettingsController und eine SettingsControllerDummy Instanz gibt (wenn beide instance() aufgerufen wurden)



  • @Jockelx Sorry, damit war SettingsControllerMockup gemeint.

    void CheckDrawerCommandTest::initTestCase()
    {
        qDebug() << "1" << (void*)&SettingsControllerMockup::instance(); 
        auto settings = static_cast<SettingsControllerMockup &>(SettingsControllerMockup::instance());
        settings.setImageProcessingSettings(&m_settingsImageProcessingDummy);
        settings.setCalibrationSettings(&m_settingsCalibrationDummy);
    }
    
    void CheckDrawerCommandTest::test_checkDrawerTest1()
    {
        qDebug() << "2" << (void*)&SettingsControllerMockup::instance();
        auto settings = static_cast<SettingsControllerMockup &>(SettingsControllerMockup::instance());
    }
    

    initTestCase() wird als erstes aufgerufen.
    Die qDebugs liefern dieselben Adressen zurück, allerdings sind beim zweiten instance-Aufruf in test_checkDrawerTest1() alle Membervariablen wieder auf nullptr. Es macht für mich absolut keinen Sinn...



  • @Steffo sagte in Frage zu Vererbung:

    SettingsControllerMockup::instance

    Code???



  • @manni66

    SettingsControllerMockup erbt von SettingsController. Den Code hatte ich weiter oben gepostet.

    class SettingsController
    {
    public:
        static SettingsController &instance()
        {
               static SettingsController singleton;
               return singleton;
        }
    }
    


  • Wie kommst du auf die Idee, du könntest SettingsController einfach mal so umcasten?



  • Du benötigst eine eigenständige SettingsControllerMockup::instance-Funktion:

    class SettingsControllerMockup
    {
    public:
        static SettingsControllerMockup& instance()
        {
               static SettingsControllerMockup singleton;
               return singleton;
        }
    }
    

    Und Singletons sind eher ein Anti-Pattern!



  • @Th69 sagte in Frage zu Vererbung:

    static SettingsControllerMockup& instance()
    {
    static SettingsControllerMockup singleton;
    return singleton;
    }

    Dann habe ich aber zwei verschiedenen Instanzen: Einmal die Mockup-Instanz und einmal die Nicht-Mockup-Instanz, die an anderer Stelle im Code aufgerufen wird.
    Ja, Singletons sind ein Antipattern, aber wie kommt man sonst von verschiedenen Stellen im Code an die Settings heran?

    @manni66
    SettingsControllerMockup erbt ja von SettingsController. Geht das nicht?



  • @Steffo sagte in Frage zu Vererbung:

    @manni66
    SettingsControllerMockup erbt ja von SettingsController. Geht das nicht?

    Nein. Ein SettingsControllerMockup ist ein SettingsController, aber ein SettingsController ist kein SettingsControllerMockup.



  • @Steffo sagte in Frage zu Vererbung:

    Ja, Singletons sind ein Antipattern, aber wie kommt man sonst von verschiedenen Stellen im Code an die Settings heran?

    Dependency Injection, für C++ z.B. mittels Boost DI. Einen Einstieg in (Boost) DI gibt es unter Boost your design with dependency injection.



  • @Th69 sagte in Frage zu Vererbung:

    Dependency Injection, für C++ z.B. mittels Boost DI. Einen Einstieg in (Boost) DI gibt es unter Boost your design with dependency injection.

    Und was hälst du selber davon?
    So auf den ersten Blick schauts nicht schlecht aus... Aber ich seh da immer noch keine "Dynamik". Wenn ich DI in Java benutzt habe, war das ausschlaggebende für mich, dass das extern konfiguriert wurde oder konfiguriert werden konnte, z.B. in XML Dateien.
    In C++ geht das so ohne weiteres nun mal nicht, und ob ich das DI von Hand mache, oder so ein Framework benutze, der Unterschied kommt mir ehrlich gesagt weitgehend marginal vor.



  • To singleton or not to singleton. Singletons sind für'n Arsch.



  • Mechanic: Mir ging es auch weniger um das konkrete Framework (oder eben doch von Hand), sondern um das Stichwort DI. In anderen Sprachen mit Reflection (wie C# oder Java) ist DI natürlich noch angenehmer zu benutzen.



  • @Steffo
    Nur mal so nebenbei... ist dir klar dass hier

    auto settings = static_cast<SettingsControllerMockup &>(SettingsControllerMockup::instance());

    settings eine Kopie ist?



  • @hustbaer sagte in Frage zu Vererbung:

    @Steffo
    Nur mal so nebenbei... ist dir klar dass hier

    auto settings = static_cast<SettingsControllerMockup &>(SettingsControllerMockup::instance());

    settings eine Kopie ist?

    Du bist echt meine Rettung! Wie viele Leute das übersehen haben? 😃 Ich hatte gedacht, eine Kopie sei nicht möglich, da ich das hier gemacht habe:

    class SettingsController
    {
    public:
        //
        // No copies of a singleton are allowed!
        //
        SettingsController(SettingsCamera const&) = delete;
        void operator=(SettingsController const&) = delete;
    
    protected:
          SettingsController();
    };
    }
    

    Aber das gilt wohl nicht für die abgeleitete Klasse?

    Danke nochmals!!! 🙂



  • @Steffo sagte in Frage zu Vererbung:

    SettingsController(SettingsCamera const&) = delete;

    Wie hängt denn die SettingsCamera mit dem SettingsController zusammen?
    Ich hätte jetzt SettingsController(SettingsController const&) = delete; erwartet.



  • @Steffo
    Wenn die Basisklasse keinen Copy-Ctor hat, dann hat die abgeleitete per Default auch keinen -- es sei denn du definierst selbst einen in der abgeleiteten Klasse. Das selbe gilt für Member, also nicht kopierbare Member machen auch per Default jede Klasse die solche Member hat nicht-kopierbar.

    Nur wie @wob schon angedeutet hat: du hast nicht den Copy-Ctor gelöscht sondern einen Konvertierungs-Ctor der eine SettingsCamera nimmt und daraus einen SettingsController bastelt. (Den du natürlich nicht hättest löschen müssen, weil so ein Ctor ja nicht implizit definiert würde.)


Log in to reply