String x = (String) tchar; casting operator overloading...



  • uuuh, wie unangenehm, ich schon wieder... sorry :-\

    aber ich muss unbedingt noch ne frage loswerden. ich will, dass tchar zu einer instanz meiner string klasse gecastet werden kann, d.h. dass folgende zeile möglich ist:
    TCHAR * x;
    String y = x; // oder muss es (String) x heißen?
    jedenfalls möchte ich folglich den String() operator für TCHAR überladen, nun meine frage, wie sieht die syntax dafür aus?
    vielen dank im vorAus
    achja, natürlich könnte ich auch operator=(TCHAR*) dafür überladen, hab ich auch schon, aber mich würde mal interessieren, wie das(siehe oben) geht.



  • class String
    {
    public:
      operator TCHAR* ()
      {
        ...
      }
      String& operator = (const TCHAR* c)
      {
        ...
      }
    }
    

    Casting Operatoren haben keinen expliziten Rückgabewert. Der wird indirekt durch den Datentyp bestimmt. Casting-Operatoren sollte man aber möglichst immer vermeiden. Denn wenn Du einen Zeiger zurückgibst, kann der implizit nach Bool gecastet werden. Und damit wird deine Klasse ungewollt mit allem vergleichbar, was sich auch nach Bool casten lässt. Ob man das will und ob das überhaupt in irgendeiner Weise Sinn macht, ist die ganz große Frage...



  • aber was ist denn, wennich die funktrion x habe, die so aussieht:
    void x(TCHAR * x);
    und ich sie so aufrufen will:
    String y;
    x(y) // bzw. x((TCHAR 😉 y);
    wie muss ich dann überladen? oder geht das nicht?
    (wie gesagt, reines interesse, natürlich könnte ich etwas wie String::GetTCHAR() schreiben)



  • Babbo schrieb:

    aber was ist denn, wennich die funktrion x habe, die so aussieht:
    void x(TCHAR * x);
    und ich sie so aufrufen will:
    String y;
    x(y) // bzw. x((TCHAR 😉 y);
    wie muss ich dann überladen? oder geht das nicht?)

    Na genau so, wie es der User mit dem (hässlichen 😉 ) leet-Nick bereits gezeigt hat.

    class Foo {
    public:
       Foo(int val):i(val) { }
       operator int*() { return &i; }   // (*)
       int i;
    };
    
    void bar(int* i) {
       cout << *i;
    }
    
    int main() {
       Foo f(13);
       bar(f);  // hier wird Foo implizit in int* per Konvertierungsoperator (*) gecastet
       cin.get();
    }
    


  • Das Problem ist, dass ein String kein Pointer (zummindest aus einem OO Sichtpunkt) ist und deshab mach eine solch Kovertirung nie genau was man will. Besser als operator TCHAR* find ich eine Methode die einen TCHAR* zurückgibt. Mit basic_string<TCHAR> würde das dann so gehen:

    basic_string<TCHAR>y;
    x(y.c_str());
    

    operator TCHAR* ist auf den ersten Blick schön aber schnell macht er absurdes:

    y+4 //pointer auf das 5te TCHAR
    if(!y) //wahr wenn operator TCHAR* 0 zurückgibt
    


  • Irgendwer schrieb:

    Das Problem ist, dass ein String kein Pointer (zummindest aus einem OO Sichtpunkt) ist und deshab mach eine solch Kovertirung nie genau was man will. Besser als operator TCHAR* find ich eine Methode die einen TCHAR* zurückgibt. Mit basic_string<TCHAR> würde das dann so gehen:

    basic_string<TCHAR>y;
    x(y.c_str());
    

    operator TCHAR* ist auf den ersten Blick schön aber schnell macht er absurdes:

    y+4 //pointer auf das 5te TCHAR
    if(!y) //wahr wenn operator TCHAR* 0 zurückgibt
    

    Babbo schrieb:

    (wie gesagt, reines interesse, natürlich könnte ich etwas wie String::GetTCHAR() schreiben)



  • XD ich habs natürlich mal wieder genau falschrum geschrieben... was ich will, ist ein operator, der einen TCHAR * in einen String (meine Klasse) konvertiert... (ich hoffe diesmal ist es richtig >.<")

    void x(String);
    TCHAR * y;
    x(y); // bzw. x((String) y);
    

    danke trotzdem für die postings...



  • Das ist einfach ein passender Konstruktor, der für TCHAR* überladen ist.

    class String {
      public:
        String(TCHAR const *);
    // ...
    };
    


  • Den Konstruktor würde ich aber explicit machen. Ansonsten kannst Du auch zuweisen. :

    TCHAR * y= irgendwas... ;
    String x;
    x = y; // Zulässig, ohne explicit
    

    Bei der Zuweisung wird einfach das alte Objekt weggeworfen und ein neues erzeugt. Die Nebenwirkungen können wirklich erstaunlich sein 🙂



  • Was sollte daran erstaunlich sein? Das ist genau das Verhalten, was ich von einer Stringklasse erwarten würde. stringVar = charPtrVar kopiert den C-String in seinen eigenen Speicher und gibt logischer Weise seinen alten frei.



  • Nein, das alte String Objekt wird zerstört. Ein neues Stringobjekt wird erzeugt, indem der C-String an den Konstruktor übergeben wird. Enthält die Stringklasse weitere Informationen, gehen diese verloren.

    Normalerweise erwartet man bei dieser Schreibweise den Zuweisungsoperator - und das ist das trügerische.

    (und genau das verhindert man mit explicit)



  • TCHAR* foo = whatever;
    
    String s = foo;  // Konstruktor erzeugt String aus foo
    s = foo;         // Zuweiungsoperator führt nötige Aufräumarbeiten aus und erzeugt
                     // neuen String aus foo
    

    Was soll hier trügerisch sein?



  • Deine sollte folgendes beinhalten

    class String{
    public:
      String();
      String(const String&);
      String(const TCHAR*);
    
      String&operator=(const String&);
      String&operator=(const TCHAR*);
    
      const TCHAR*c_str()const;
      //THCAR*c_str(); keine gute Idee da das ja alle Probleme eines TCHAR[] hat
    
      //operator TCHAR*(); keine gute Idee zur Begründung sieh mein letzter Post
    
      ~String();
    };
    

    String(const TCHAR*arg) sollte arg auf keinen Fall deleten! Sonst wird das zum Problem:

    String str(L"Hello");//Bum L"Hello" liegt nicht im Heap
    

    Ansonten noch ein kleiner Tip. Im op= sollte new immer vor delete aufgerufen werden. Also:

    TCHAR*new_buffer=new TCHAR[...];
    delete[]buffer;
    buffer=new_buffer;
    

    Wenn du es andersrum machst und new wirft eine Exception ist dein String irreparabel futsch, so ist nur die Zuweisung gescheitert.

    Und beachte, dass beim delete ein [] steht. Bei manchen Compilern kann es bum machen wenn der nicht da ist.



  • TCHAR* foo = whatever;
    
    String s = foo;  // Konstruktor erzeugt String aus foo
    s = foo;         // Alter String wird zerstört. Konstruktor legt durch implizite Typumwandlung einen neuen String an.
    

    So ist es richtig. Immer vorrausgesetzt, es gibt keinen Zuweisungsoperator. Das ist richtiger und gültiger Code.

    Stell Dir vor, deine Stringklasse speichert nicht nur den String sondern noch andere x-beliebige Informationen, die irgendwie mit der Klasse zusammenhängen. Diese gehen bei so einem Aufruf mal eben verloren. Da man aus dieser Schreibweise nicht offensichtlich erkennen kann, was da nun eigenltich aufgerufen wird, ist es so gefährlich.



  • 7H3 N4C3R schrieb:

    Stell Dir vor, deine Stringklasse speichert nicht nur den String sondern noch andere x-beliebige Informationen, die irgendwie mit der Klasse zusammenhängen. Diese gehen bei so einem Aufruf mal eben verloren. Da man aus dieser Schreibweise nicht offensichtlich erkennen kann, was da nun eigenltich aufgerufen wird, ist es so gefährlich.

    Eine Stringklasse ist keine Stringklasse wenn sie mehr tut als eine Stringklasse tut! Also muss der Ctor sämtliche Informationen vom TCHAR* herleiten können.

    Das einzige was mich an dem Code stört ist, dass der op= ja die op=s aller Member aufruft. Und beim Pointer auf den Buffer wird da ein delete nicht aufgerufen => Speicherloch.



  • 7H3 N4C3R schrieb:

    Stell Dir vor, deine Stringklasse speichert nicht nur den String sondern noch andere x-beliebige Informationen, die irgendwie mit der Klasse zusammenhängen. Diese gehen bei so einem Aufruf mal eben verloren. Da man aus dieser Schreibweise nicht offensichtlich erkennen kann, was da nun eigenltich aufgerufen wird, ist es so gefährlich.

    Eine Stringklasse ist keine Stringklasse wenn sie mehr tut als eine Stringklasse tut! Also muss der Ctor sämtliche Informationen vom TCHAR* herleiten können.

    Das einzige was mich an dem Code stört ist, dass der default op= ja die op=s aller Member aufruft. Und beim Pointer auf den Buffer wird da ein delete nicht aufgerufen => Speicherloch.



  • 7H3 N4C3R schrieb:

    TCHAR* foo = whatever;
    
    String s = foo;  // Konstruktor erzeugt String aus foo
    s = foo;         // Alter String wird zerstört. Konstruktor legt durch implizite Typumwandlung einen neuen String an.
    

    So ist es richtig. Immer vorrausgesetzt, es gibt keinen Zuweisungsoperator. Das ist richtiger und gültiger Code.

    Stell Dir vor, deine Stringklasse speichert nicht nur den String sondern noch andere x-beliebige Informationen, die irgendwie mit der Klasse zusammenhängen. Diese gehen bei so einem Aufruf mal eben verloren. Da man aus dieser Schreibweise nicht offensichtlich erkennen kann, was da nun eigenltich aufgerufen wird, ist es so gefährlich.

    Ich weiß nach wie vor nicht was du meinst. Erstens macht die Zeile "s = foo" Gebrauch von einem Zuweisungsoperator und 2. kann deine Stringklasse Millionen von weiteren Infos haben - alles kein Problem wenn man operator= entsprechend überlädt.



  • Erstens macht die Zeile "s = foo" Gebrauch von einem Zuweisungsoperator

    Wenn man einen definiert hat. Wenn nicht, und es gibt einen Konstruktor, der den Datentyp annehmen kann, so wird dieser ausgeführt. Probier es aus.



  • 7H3 N4C3R schrieb:

    Erstens macht die Zeile "s = foo" Gebrauch von einem Zuweisungsoperator

    Wenn man einen definiert hat. Wenn nicht, und es gibt einen Konstruktor, der den Datentyp annehmen kann, so wird dieser ausgeführt. Probier es aus.

    Na davon bin ich ja ausgegangen, sonst ist die Klasse sowieso Schrott.



  • 7H3 N4C3R schrieb:

    Erstens macht die Zeile "s = foo" Gebrauch von einem Zuweisungsoperator

    Wenn man einen definiert hat. Wenn nicht, und es gibt einen Konstruktor, der den Datentyp annehmen kann, so wird dieser ausgeführt. Probier es aus.

    ganz so einfach ist es auch nicht.

    String s = "foo";
    

    das ruft dir garantiert den konstruktor auf (wenn es einen passenden gibt)

    String s;
    s = "foo";
    

    das ruft entweder den passenden zuweisungsoperator auf oder - falls es den nicht gibt - konstruiert aus "foo" ein temporäres objekt und weist das dann über den zuweisungsoperator "String &operator = (const String &)" (der übrigens implizit generiert wird) letztendlich an s zu.

    also: den normalwerweise implizit generierten zuweisungsoperator undefiniert lassen (bringt natürlich eine gewisse einschränkung), bzw. ihn als String &operator = (String &) deklarieren, oder den konstruktor explicit machen, oder einen eigenen passenden zuweisungsoperator definieren, der diese hässliche implizite umwandlung unterdrückt.


Log in to reply