Eigene Typumwandlung programmieren



  • Hey Leute,

    was ich versuche zu finden ist ein Weg wie ich eine eigene Typumwandlung programmieren kann. Das soll heißen: ich möchte eine Funktion schreiben, die sowohl eine implizite als auch explizite Umwandlung eines Objektes vom Typ x in Typ y erlaubt.

    Wie stellt man sowas an? Und ist es überhaupt machbar eine implizite Umwandlung im nachhinein festzulegen? Und kann man damit auch vom Compieler vorgegebene implizite Umwandlungen "überschreiben"?



  • Naja, wenn du deine Klasse hast kannst du Nicht-Explizite Konstruktoren anbieten. Und du kannst cast-Operatoren anbieten:

    class Foo
    {
    public:
        Foo(int i) {} // nun kann implizit von int nach Foo gecastet werden
    
        operator int(){ return 0;} // jetzt kannst du nach int casten
    };
    

    Aber damit passt man beser sehr sehr sehr sehr gut auf. Du wirst das eher weniger komplett überblicken können und siehst nicht die Fehlerfallen und Stolperdrähte, die dadurch gespannt werden.



  • Also wäre ein Cast von Klasse ECI zu Klasse ECEF möglich indem man

    class ECI
    {
    public :
    operator ECEF { mach was; return ECEF;};
    };
    

    angibt? Worauf ist da zu achten, wenn du sagst da übersieht man viele Stolpersteine?



  • class Bar
    {
    public:
    	Bar(int i){}
    
    	operator float() {return 0;}
    };
    
    void foo(double d){}
    void foo(Bar b) {}
    
    int main()
    {
    	foo(5); //was wird aufgerufen?
    
    	foo(Bar(4)); // was wird hier aufgerufen?
    }
    

    Der Compiler warnt dich halt nicht mehr. Du kannst unter Umständen das Typsystem austricksen, was sich später rächen wird.

    Edit: Das sind von mir schlechte Beispiele, ich hab selbst keine praktischen Erfahrungen, nur die Theorie. Bin halt selbst noch nie über diese Problematik gestolpert.



  • Skym0sh0: Wo ist denn nun die Problematik bei Deinem Code?
    Beim ersten Aufruf wird foo(double) ausgeführt, beim zweiten (solange Du nicht explizit castest) wird foo(Bar) ausgeführt.

    Oder ist bei der "Problematik" damit gemeint, dass man erwarten würde, dass foo(double) zweimal ausgeführt werden sollte?



  • Skym0sh0 schrieb:

    Edit: Das sind von mir schlechte Beispiele, ich hab selbst keine praktischen Erfahrungen, nur die Theorie. Bin halt selbst noch nie über diese Problematik gestolpert.

    macht nix. das hilft mir erstmal weiter. Ich werde einfach mal rumprobieren. Es sind auch nicht extrem schwierige Umwandlungen, allerdings macht es sich doch ganz gut bei mir wenn ich die implizit durchführen kann. Danke erstmal für die Hilfe!



  • gnihihihihi schrieb:

    Skym0sh0: Wo ist denn nun die Problematik bei Deinem Code?
    Beim ersten Aufruf wird foo(double) ausgeführt, beim zweiten (solange Du nicht explizit castest) wird foo(Bar) ausgeführt.

    Oder ist bei der "Problematik" damit gemeint, dass man erwarten würde, dass foo(double) zweimal ausgeführt werden sollte?

    Ja, das ist ja noch offensichtlich.

    Und wenn man nun eine der beiden foo's weglässt?
    Was erwartet man dann oder hofft man dann?

    Hoffentlich kommt dann ein Error oder eine Warnung.

    Wird aber nicht kommen, leider.

    Bei solch kleinen überschaubaren Beispielen geht das ja noch. Aber bei mehreren Klassen und gegenseitigen impliziten casts ist das dann schon sehr komplex. (Ich nenne als Hausnummer einfach mal eine Zahl von, sagen wir, 10000 Klassen. Wird das dann irgendjemand von hier überblicken können? Nein!)



  • Früher fand ich implizite Typumwandlung was ganz feines. Inzwischen verwende ich es sehr sparsam. Es gibt zu viele Situationen, wo eine implizite Umwandlung versehentlich von statten geht. Die Typsicherheit von C++ ist schon was feines. Er schützt an vielen Fällen vor Fehlern. Mit einer impliziten Typumwandlung hebele ich diesen Mechanismus aus. Ich versuche mich mal an einem verbesserten Beispiel:

    class Bar
    {
    public:
        Bar();
        operator double();
    };
    
    void foo(double d);
    void foo(Bar b);
    
    int main()
    {
        Bar b;
        foo(b);   // hier wird foo(Bar) aufgerufen
                  // wenn ich vergesse, den Header einzubinden, der foo(Bar) deklariert
                  // dann wird foo(double) aufgerufen
    }
    

    Der Code ist abhängig davon, welche Header ich einbinde. Solche Situationen können sehr subtil sein. Wenn dann noch Operatorüberladung hinzu kommt, taugt das für einen Test, wie gut man C++ beherrscht, aber nicht für produktiven Code, den jemand auf dem ersten Blick noch verstehen soll.

    Implizite Typumwandung ist wie auch die Operatorüberladung ein sehr interessantes Konzept mit interessanten Möglichkeiten. Aber es sind genau die Stellen, womit man sich mit C++ ins Knie schießen kann. Man sollte wirklich sparsam damit um gehen.


Anmelden zum Antworten