Konvertierungen



  • Hi 🙂

    Ich hab so meine Probleme damit zu erkennen, wann eine implizite und wann eine explizite Konvertierung vorliegt.

    Mal ein Beispiel:

    X::X(long l)
    {
    }
    X::X(unsigned long l)
    {
    }
    X::X(string s)
    {
    }
    X::X()
    {
    }
    X x0(1.2);  // explizit
    X x1{1.2};  // Fehlermeldung
    X x2 = 1.2; // implizit
    

    Kann mir bitte wer diese letzten 3 Zeilen erklären, warum das explizit oder implizit ist?


  • Mod

    Explizit: Du deutest den Cast syntaktisch an (C-Cast, C++-Casts), oder du nutzt Direktinitialisierung, welche durch die Klammern bei der Initialisierung gekennzeichnet ist.

    Implizit ist es in der dritten Zeile, da du eine Zuweisung in der Initialisierung verwendest. Das nennt man Kopierinitialisierung (engl. copy initialization) und ist eine implizite Konvertierung, da es dieselbe Form von Initialisierung ist, wie sie auch beim Kopieren von Funktionsargumenten bzw. Rückgabewerten, Exceptions usw. vorhanden ist.

    X x1{1.2};  // Fehlermeldung
    

    Nicht seit C++11.
    Edit: Doch, es ist ja mehrdeutig...



  • Also die Zeile 13 kapiert ich immer noch nicht. Normalerweise verwendet man bei einem expliziten cast doch immer spezielle Typumwandlungsoperatoren, wie z. B. static_cast. Aber hier sehe ich keine 😕

    Das hier ist für mich z. B. eine typische explizite Typumwandlung:

    double dwert = 9.1;
    int iwert = static_cast<int>(dwert);
    


  • Herb Sutter empfehle ich beid er Fragestellung noch grad mal...



  • Habe grad gesehen, dass es scheinbar auch noch eine andere Variante gibt, Zahlen zu konvertieren:

    int ival1, ival2 = 2;
    float fval1 = 3.5f;
    
    cout << fval1/ival2 << '\n'; // => 1.75
    cout << int(fval1)/ival2 << '\n'; //  => 1
    cout << int(fval1)/float(ival2) << '\n'; //  => 1.5
    

    Ich verstehe aber nicht, wie man auf die letzten beiden Ergebnisse kommt 😕

    Sind diese int() und float() Konverierungen schon deprecated? Soll man statt dessen im C++11 nur noch static_cast für solche Zahlenkonvertierungen verwenden?



  • cout << int(fval1)/ival2 << '\n'; // => 1

    Aufgrund int() hat man 3. 3 / 2 = 1.5
    Weil 3 und 2 int-Werte sind, ist dann auch das Ergebnis wieder ein int-Wert? Also 1?

    cout << int(fval1)/float(ival2) << '\n'; // 1.5

    Hier hat man wieder 3 / 2. Aber eine von den beiden Zahlen ist ein float. Darum bleibt es beim float-Wert 1.5?

    Stimmt das??


  • Mod

    Aufgrund int() hat man 3. 3 / 2 = 1.5

    Wenn Fließkommazahlen in integrale Typen konvertiert werden, wird der Nachkommateil einfach "abgeschnitten", sprich die Division ist 3 / 2, das ist 1.5. Und da der Typ des Divisionsausdrucks wieder integral ist, wird der Nachkommateil abgeschnitten, und es ergibt sich 1.

    Darum bleibt es beim float-Wert 1.5?

    Jup.



  • Danke 🙂

    Und wie schaut es mit diesen Konvertierungsfunktionen int() und float() aus? Sind die in C++11 deprecated?



  • Ich weiß nicht, ob die casts schon per Standard deprecated sind. Allerdings wird von ihnen angeraten. Nimm stattdessen einfach static_cast.



  • tröröö schrieb:

    Sind die in C++11 deprecated?

    Nein, sie sind auch in C++98 nícht deprecated.
    Man sollte sie nur nicht verwenden. Um mal eben einen float zu einem int zu machen, ist das ok, aber auf gar keinen Fall verwenden wenn Pointer oder UDTs beteiligt sind.



  • Ok, danke 🙂


  • Mod

    Nathan schrieb:

    Um mal eben einen float zu einem int zu machen, ist das ok, aber auf gar keinen Fall verwenden wenn Pointer oder UDTs beteiligt sind.

    std::string("asdf")
    


  • Arcoth schrieb:

    Nathan schrieb:

    Um mal eben einen float zu einem int zu machen, ist das ok, aber auf gar keinen Fall verwenden wenn Pointer oder UDTs beteiligt sind.

    std::string("asdf")
    

    Arcoth, das ist ein Konstruktoraufruf. Kein cast.



  • Nathan schrieb:

    Arcoth schrieb:

    std::string("asdf")
    

    Arcoth, das ist ein Konstruktoraufruf. Kein cast.

    Hätte ich auch gesagt. Scott Meyers sagt in Effective C++ allerdings dass das ein Cast ist.

    #include <iostream>
    #include <string>
    
    int main(){
    	std::cout << (std::string)"hello";
    	std::cout << static_cast<std::string>("world");
    }
    

    Ideone

    Scheinbar ist das aus C++-Sicht dasselbe.



  • Dann kanns nur eine Konstruktoraufrufcast sein.



  • T(exp) ist der sog. "function style cast". Der gleich mächtig ist wie der C-style Cast.
    Leider:

    typedef void* VoidPtr;
    int main()
    {
        int i = 123;
        VoidPtr v = VoidPtr(i); // OK, das selbe wie (VoidPtr)i
        return 0;
    }
    

    Die Schreibweise ansich ist ja OK, aber dass man damit alles machen kann was ein C-style Cast auch macht, finde ich schon etwas übertrieben.


  • Mod

    Nathan schrieb:

    Arcoth, das ist ein Konstruktoraufruf. Kein cast.

    Das ist Identisch. Du castest einen char const* nach std::string . Was denkst du, was ein Cast ist?



  • Arcoth schrieb:

    Nathan schrieb:

    Arcoth, das ist ein Konstruktoraufruf. Kein cast.

    Das ist Identisch. Du castest einen char const* nach std::string . Was denkst du, was ein Cast ist?

    Ja, das Prinzip ist das ähnliche.
    Aber bei std::string("foo") wird C++-Code aufgerufen, der sicher geschrieben wurde und fehlergeprüft sind.
    Wohingegen die Casts im eigentlichem Sinne u.U. irgendwelche Bitumrepräsentation sind.


  • Mod

    Nathan schrieb:

    Wohingegen die Casts im eigentlichem Sinne u.U. irgendwelche Bitumrepräsentation sind.

    static_cast<double>(int_wert)
    

  • Mod

    Nathan schrieb:

    Wohingegen die Casts im eigentlichem Sinne u.U. irgendwelche Bitumrepräsentation sind.

    Schon wenn du nur einen unsigned zu int castest, kann keine simple Bitumrepräsentation am Werk sein.

    Ja, das Prinzip ist das ähnliche.

    Nein, es ist haargenau das gleiche. Ein Cast ist eigentlich nur eine Erstellung und Initialisierung einer Temporary mit dem gegebenen Operanden.
    Edit:

    N3797 §5.2.3/1 schrieb:

    the expression T(x1, x2, ...) is equivalent in effect to the declaration T t(x1, x2, ...); for some invented temporary variable t, with the result being the value of t as a prvalue.


Log in to reply