Design-Frage bzg. Mehrdeutigkeiten bei Konvertierungen



  • Servus zusammen,

    Folgender Code, der verständlicherweise ja so nicht compiliert, da bei der If-Abfrage in der main()-Funktion der rechte Operand ja mithilfe des Konvertierungs-Ctor's in einen Foo konvertiert werden kann und der linke Operand mithilfe der Konvertierungs-Funktion in einen bool...

    #include <iostream>
    using namespace std;
    
    template<class T>
    class Foo
    {
            T value;
    
            public:
                    Foo() { }
                    Foo(const T& v) : value(v) { }
    
                    const T& get_value() const { return value; }
    
                    bool operator!=(const Foo<T>& rhs) { return (value != rhs.value); }
                    operator bool() const { return (value != 0); }
    };
    
    int main()
    {
            Foo<int> obj1(9);
            const int k = 0;
    
            cout << "\n obj1 (" << obj1.get_value() << ") is ";
            if(obj1 != k)
                    cout << "!=";
            else
                    cout << "==";
            cout << " k (" << k << ")\n";
    
            return 0;
    }
    

    Meine Frage an euch: Wie schließt ihr solche Mehrdeutigkeiten aus wenn ihr sowohl das Objekt in einen anderen Datentyp konvertieren als auch aus einem anderen Datentyp dieses Objekt konstruieren müsst?

    Scott Meyers sagt dazu (IIRC) ja 'nur': "Vermeiden sie potentielle Mehrdeutigkeiten".

    Aber wie macht _ihr_ das genau bzw. was haltet ihr für das beste Design?

    • Konvertierungs-Konstruktoren als explicit deklarieren.
    • Statt Konvertierungs-Funktionen eine Methode a la "bool as_bool() const;" definieren.
    • Beide oben genannten Dinge.
    • So wie im obigen Code und dann gegebenenfalls explizit casten.
    • Design der Klasse, etc. komplett verändern um die oben genannte Problemstellung auch anders zu lösen.
    • keins von den obigen, sondern...

    Ich freue mich auf rege Antworten!

    Caipi



  • [*]Konvertierungs-Konstruktoren als explicit deklarieren.
    ja, aber nur, wo ich mir den wert nicht als "was einfaches" vorstelle. also Array a=10; ist falsch, weil das array nicht den wert 10 kriegt. aber string s="10"; oder Bruchzahl b=10; ist richtig.

    [*]Statt Konvertierungs-Funktionen eine Methode a la "bool as_bool() const;" definieren.
    ja. im allgemeinen schon. schade, daß man den operator bool nicht explicit machen kann, womit ich meine, er sollte nur beim explziten casten wirken.



  • Hallo,
    ich verwende statt operator bool eigentlich immer einen operator unspecified_bool_type. Wobei unspecified_bool_type dann ein Pointer-Type ist (am Besten ein Type Pointer-to-Member(funktion))

    class Foo
    {
    typedef void (Foo::*unspecified_bool_type)();
    public:
        void aFunc();
    
        operator unspecified_bool_type() const {
            return bedingung ? &Foo::aFunc : static_cast<unspecified_bool_type>(0);
        }
    };
    

    So kann man Foo-Objekte nach wie vor in Bedingungen verwenden, aber nicht ausversehen als ganzzahligen Wert.



  • Die Typumwandlungs-Operatoren sollte man wirklich nur dann überschreiben wenn das Objekt auch in Form eines Objekts des anderen Typs abgebildet werden kann.

    Ein Haus z.B. kann ich nicht durch einen Bool-Wert beschreiben. Also würde ich für diesen Fall keine Typumwandlung implementieren, sondern Funktionen hierfür schreiben (z.B. IsEmpty (), IsWriteEnable(), IsBuild (), ....)

    Typumwandlungs-Operatoren würde ich z.B. für die Klasse PI implementieren, da die Objekte dieser Klass auch als Zahl des Typs float oder double verwendet werden können.



  • @volkard, HumeSikkins und Mathias:
    Vielen Dank für eure Antworten. Hume's Vorschlag muss ich jetzt mal testen... 🙂

    Caipi


Anmelden zum Antworten