Im Konstruktor Initialisierung von Objekt entscheiden



  • Hallo ihr Lieben,

    ein kleines Minimalbeispiel:

    In der Klasse dummy in Zeile 21 wird in Zeile 26 bzw. 27 ein Objekt _d initialisiert, dass entweder nach der Blaupause von foo oder bar entworfen wird. Dies kann ich durch auskommentieren steuern.

    Jetzt aber die Frage: Kann ich das nicht auch über den Konstruktor entscheiden? Also ich initialisiere z.B. die Klasse dummy mittels dummy d(bar) und dadurch wird _d anhand von bar initialisiert?

    #include <iostream>
    
    class foo
    {
    	public:
    		foo():_d(1.0){}
    		double operator()(){ return _d; }
    	private:
    		double _d;
    };
    
    class bar
    {
    	public:
    		bar():_d(2.0){}
    		double operator()(){ return _d; }
    	private:
    		double _d;
    };
    
    class dummy
    {
    	public:
    		double operator()(){ return _d(); }
    	private:
    		foo _d;
    		//bar _d;
    };
    
    int main()
    {
    	dummy d;
    
    	std::cout << d() << std::endl;
    
    	return 0;
    }
    

    Gruß,
    -- Klaus.



  • Ja, das geht. Aber nicht so, wie du es jetzt hast.
    Denn du kannst den Typen von _d nicht ohne weiters nach bar oder foo ändern.
    Dafür braucht man Vererbung und Polymorphie.



  • da foo und bar nicht polymorph sind, steht auch zu compilezeit fest, welchen typ das argument hat, mit welchem du den konstruktor aufrufst. folglich kann man schreiben:

    template<typename T>
    class dummy
    {
            T _d;
        public:
            explicit dummy(T const& Rhs)
                : _d(Rhs)
            {
            }
            double operator()(){ return _d(); }
    };
    

    ich weiss, das ist etwas mühsam dass man immer den typen explizit angeben muss aber es hat dafür keinen laufzeit-overhead.



  • Wollte gerade ein Template-Codebeispiel posten, gerade noch rechtzeitig gesehen, dass mir schon jemand die Arbeit abgenommen hat 😉

    In dem geposteten Beispiel sollte der Template-Parameter automatisch ermitelt werden können, eine explizite Angabe sollte nicht nötig sein.



  • Für mich klang das so, dass er das zur Runtime entscheidet haben möchte, bpsw. via einem bool Flag oder so.
    Naja, mal gucken, was er dazu sagt.



  • daddy_felix schrieb:

    In dem geposteten Beispiel sollte der Template-Parameter automatisch ermitelt werden können, eine explizite Angabe sollte nicht nötig sein.

    ich bin mir jetzt nicht 100% sicher aber ich glaube, dass klassen-template-argumente nicht anhand des konstruktors deduziert werden (können). ansonsten könnte man decltype schon in c++03 implementieren.


  • Mod

    asfdlol schrieb:

    daddy_felix schrieb:

    In dem geposteten Beispiel sollte der Template-Parameter automatisch ermitelt werden können, eine explizite Angabe sollte nicht nötig sein.

    ich bin mir jetzt nicht 100% sicher aber ich glaube, dass klassen-template-argumente nicht anhand des konstruktors deduziert werden (können). ansonsten könnte man decltype schon in c++03 implementieren.

    Du kannst dir 100% sicher sein.
    Schließlich müssen die Parameter des Klassentemplates bekannt sein, um überhaupt erst ermitteln zu können, welche Konstruktoren die jeweilige Spezialisierung hat.

    Klaus82 schrieb:

    Jetzt aber die Frage: Kann ich das nicht auch über den Konstruktor entscheiden? Also ich initialisiere z.B. die Klasse dummy mittels dummy d(bar) und dadurch wird _d anhand von bar initialisiert?

    Im Prinzip schon, falls du C++11 verwendest. Allerdings sollte das sehr gut überlegt sein, weil dann die Speicherverwaltung in der Klasse selbst implementiert werden muss.

    ungefähr so:

    class dummy
    {
        public:
            dummy(foo x) : is_foo(true), foo_d{x} {}
            dummy(bar x) : is_foo(false), bar_d{x} {}
            dummy(const dummy& other) : is_foo(other.is_foo)
            {
                is_foo ? (void*)new((void*)&foo_d)foo(other.foo_d) : (void*)new((void*)&bar_d)bar(other.bar_d);
            }
            dummy& operator=(const bar& rhs)
            {
    ...
            }
            ~dummy() { is_foo ? foo_d.~foo() : bar_d.~bar(); }
            double operator()(){ return is_foo ? bar_d() : foo_d(); }
        private:
            bool is_foo;
            union {
                foo foo_d;
                bar bar_d;
            };
    };
    

    wahrscheinlich falsch, sollte aber das Prinzip klarmachen. In 95% der Fälle dürfte es eine schlechte Idee sein.


Anmelden zum Antworten