Frage bzg. template Funktionen



  • Hi!
    Ich habe die 3 Klassen:

    class base {...};
    class derived1: public base {...};
    class derived2: public base {...};
    

    Sagen wir mal, dass ich eine Funktion habe:

    void f() {...}
    

    Die Implementation von f muss 1 bestimmtes Objekt erstellen vom Typ, abgeleitet von der Klasse base. So etwas:

    void f() { base* = new derivedX; }
    

    Wie kann ich das Typ "derived" als template der Funktion f übergeben?
    Ich möchte etwas wie f<derived1>() z.B. haben...



  • Zdravko schrieb:

    ...
    Ich möchte etwas wie f<derived1>() z.B. haben...

    Dann mach das doch ! 😃

    template <typename T>
    T* f() { return new T; }
    

    AAAABER: Das halte ich für designtechnisch für "ungünstig".
    Spontan fällt mir ein:

    • Wenn Du Konstuktoren mit unterschiedlichen Parametern hastm wird's lästig.
    • Wem "gehört" das erzeugte Objekt (= Wer soll das deleten) ? So eine "Verantwortungsübergabe" ist beliebte Fehlerquelle (irgendeiner löscht (nicht), wo er (nicht) soll).
    • Wozu eine eigene Funktion, wenn man doch sogar schon ein Schlüsselwort (new) dafür hat ? Kürzer wird's dadurch nicht und übersichtlicher auch nicht.
    • ...

    Gruß,

    Simon2.



  • Du hast mich falsch verstanden. Der template Parameter kann nicht beliebig sein, sondern er muss eine abgeleitete von base Klasse sein.
    Die Konstruktoren aller abgeleiteten Klasse haben die selben Parameter.
    Die Funktion erstellt ein Objekt und (mit Sicherheit!) löscht sie es egal was passiert.



  • Zdravko schrieb:

    Du hast mich falsch verstanden. Der template Parameter kann nicht beliebig sein, sondern er muss eine abgeleitete von base Klasse sein.

    Wenn Du in der Funktion "base* p = new T" machst, wird sich der Compiler schon beschweren, wenn T* nicht in base* konvertiert werden kann (und das ist nur der Fall, wenn sie verwandt sind).



  • Zdravko schrieb:

    Die Funktion erstellt ein Objekt und (mit Sicherheit!) löscht sie es egal was passiert.

    Zdravko schrieb:

    void f() { 
      base* = new derivedX; 
    }
    

    Dir ist hoffentlich klar, dass "mit Sicherheit gelöscht" bei einem einfachen Pointer bedeutet, dass alle Operationen zwischen new und delete die "nofail"-Garatie bieten müssen, d.h. auf keinen Fall exceptions auslösen dürfen? Falls auch nur eine Operation eine Exception auslösen kann, solltest du besser einen shared_ptr<base> benutzen.



  • Zdravko schrieb:

    ...
    Die Konstruktoren aller abgeleiteten Klasse haben die selben Parameter...

    Woher willst Du das wissen ?
    Bist Du der einzige, der jemals ableiten wird ?

    Zdravko schrieb:

    ...
    ...Die Funktion erstellt ein Objekt und (mit Sicherheit!) löscht sie es egal was passiert.

    Wie löscht "die Funktion" denn das Objekt, wenn es nach ihrem Ablauf noch gültig sein soll ?

    Aber ich habe den Eindruck, dass hier 2 Dinge zu klären sind:
    1.) "Wie kann ich sicherstellen, dass eine (ein Funktionstemplate instantiierende) Klasse von einer bestimmten Basis abgeleitet ist ?" und
    2.) "Wann sind 'Erzeugerfunktionen' sinnvoll ?"

    Für Ersteres gibt es schon ein paar Dinge hier im Forum. Mein Einwand bezog sich im Wesentlichen auf die 2. Frage.
    (Natürlich gibt es "Factorys" und das ist auch gut so ... aber oftmals werden 'Erzeugerfunktionen' von Anfängern eingesetzt, weil es ihnen einfacher erscheint als der direkte Einsatz von new)

    Gruß,

    Simon2.



  • LordJaxom schrieb:

    Zdravko schrieb:

    Du hast mich falsch verstanden. Der template Parameter kann nicht beliebig sein, sondern er muss eine abgeleitete von base Klasse sein.

    Wenn Du in der Funktion "base* p = new T" machst, wird sich der Compiler schon beschweren, wenn T* nicht in base* konvertiert werden kann (und das ist nur der Fall, wenn sie verwandt sind).

    Aha, ok. Danke! Das wars.

    @Simon2, wer redet hier von 'Erzeugerfunktionen'? Wenn die Funktion f mit ungültiger Klasse instanziert wird, sprich nicht abgeleitet von base, oder der Konstruktor braucht andere Parameter, dann wird es einfach nicht kompiliert. So was nennt man "Invarianz der Policy (auch Traits in C++)".



  • Zdravko schrieb:

    ...wer redet hier von 'Erzeugerfunktionen'? ...

    Ich - sorry, mein Fehler. Ich habe oben falsch gelesen:

    base* f() { return new derivedX; }
    

    ... das hattest Du aber weder geschrieben noch gemeint.
    => Ich nehme alles zurück und behaupte das Gegenteil.

    Tut mir leid,

    Simon2.



  • Ist schon ok. Jedem kann es passieren.
    Ich selbst finde meine Idee schon dumm.


Anmelden zum Antworten