2009-10-24 8 views
5

In C++ ist es möglich, Konvertierungsoperatoren zu definieren, die keine Klassenmitglieder sind? Ich weiß, wie man das für reguläre Operatoren (wie +) macht, aber nicht für Konvertierungsoperatoren.C++ benutzerdefinierte Konvertierungsoperatoren ohne Klassen?

Hier ist mein Anwendungsfall: Ich arbeite mit einer C-Bibliothek, die mir eine PA_Unichar * aushändigt, wo die Bibliothek PA_Unichar zu einem 16-Bit-int definiert. Es ist eigentlich eine Zeichenfolge, die in UTF-16 codiert ist. Ich möchte es in eine std::string konvertieren, die in UTF-8 codiert ist. Ich habe alle der Conversion-Code bereit und arbeiten, und ich bin nur die syntaktische Zucker fehlen, die mir schreiben lassen würde:

PA_Unichar *libOutput = theLibraryFunction(); 
std::string myString = libOutput; 

(in der Regel ohne die temporäre Variable in einer Zeile).

Auch erwähnenswert:

  • Ich weiß, dass std::string nicht implizite Konvertierung von char* nicht definiert, und ich weiß, warum. Der gleiche Grund könnte hier gelten, aber das ist nebensächlich.

  • Ich habe eine ustring, Unterklasse von std::string, die den richtigen Konvertierungsoperator aus PA_Unichar* definiert. Es funktioniert, aber dies bedeutet ustring Variablen anstelle von std::string und dann erfordert Konvertierung in std::string, wenn ich diese Zeichenfolgen mit anderen Bibliotheken verwenden. Das hilft also nicht sehr.

  • Die Verwendung eines Zuweisungsoperators funktioniert nicht, da Klassenmitglieder sein müssen.

So ist es möglich, implizite Konvertierung Operatoren zwischen zwei Typen definieren Sie nicht kontrollieren (in meinem Fall PA_Unichar* und std::string), die nicht Klassentypen sind oder nicht?

Wenn nicht, was könnte Workarounds sein?

Antwort

8

Was ist los mit einer freien Funktion?

std::string convert(PA_Unichar *libOutput); 

std::string myString = convert(theLibraryFunction()); 

bearbeiten Beantwortung auf den Kommentar:

Als DrPizza says: Alle anderen versucht, die Löcher durch implizite Konvertierungen geöffnet zu stopfen durch sie mit denen explizite Konvertierung zu ersetzen, die Sie „visuelle Unordnung“ nennen.

Was die temporäre Zeichenfolge: Warten Sie auf die nächste Compiler-Version. Es wird wahrscheinlich mit Rvalue-Referenzen kommen und seine std::string Implementierung wird zusätzlich eine Verschiebungssemantik implementieren, die die Kopie eliminiert. Ich habe noch eine billigere Möglichkeit gesehen, um Ihren Code zu beschleunigen, als wenn Sie einfach auf eine neue Compiler-Version aktualisieren.

+0

was ist los? Nicht viel, aber immer noch, zwei Dinge: - das visuelle Durcheinander, wenn Sie Hunderte von sinnlosen Calls zu konvertieren haben - diese Lösung impliziert die Verwendung eines temporären std :: string. Dies bedeutet, dass die Daten die ganze Zeit zweimal kopiert werden. Dies kann oder kann kein Problem sein, ist aber nicht sehr befriedigend. –

+6

Die meisten Compiler optimieren die zusätzliche Kopie. – rlbond

+4

jdmuys> rlbond ist richtig, RVO ist in der Praxis üblich und real. Sie könnten wandeln, um das zu lesen: http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/ – Klaim

4

Ich glaube nicht, dass Sie "globale" Konvertierungsoperatoren definieren können. Die Standards sagen, dass conversion functionsspecial member functions sind. Ich würde die folgende propse, wenn ich die folgende Syntax Zucker in Erwägung ziehen könnte:

struct mystring : public string 
{ 
    mystring(PA_Unichar * utf16_string) 
    { 
     // All string functionality is present in your mystring. 
     // All what you have to do is to write the conversion process. 
     string::operator=("Hello World!"); 
     string::push_back('!'); 
     // any string operation... 
    } 
}; 

Beachten Sie, dass polymorphe Verhalten dieser Klasse gebrochen ist.Solange Sie kein Objekt über einen Zeiger vom Typ string* erstellen, sind Sie in der sicheren Seite! Also, dieser Code ist perfekt:

Wie schon gesagt, der folgende Code ist kaputt!

string* str = new mystring(....); 
.... 
delete str; // only deleting "string", but not "mystring" part of the object 
// std::string doesn't define virtual destructor 
5

Implizite Konvertierungen sind sowieso der Teufel. Machen Sie es explizit mit einem Conversion-Funktionsaufruf.

+4

Nun, es kommt darauf an. Es gibt reale Situationen, in denen implizite Konvertierungen sinnvoll sind. Ich benutze sie typischerweise zum Beispiel, um einen Typ in einen anderen zu konvertieren, der semantisch eine Untermenge des anderen darstellt. Wenn Sie zum Beispiel eine "Person" -Klasse und einen "Angestellten" haben, würde ich erwarten, dass "Mitarbeiter" automatisch zu "Person" konvertiert, wo immer diese erwartet wird. (Umgekehrt wäre eine umgekehrte Konvertierung im Umkehrschluss natürlich eine schlechte Idee.) – Mephane

+1

Mir ist klar, dass Sie nur ein hypothetisches Beispiel vorgeschlagen haben, aber der Mitarbeiter als Unterklasse der Person ist ein schlechtes Design und ein Liebling Bergwerk. Subclassing wird für eine is-a-Beziehung verwendet. Es scheint, dass ein Mitarbeiter eine Person ist, aber das ist nur ein Teil der Mehrdeutigkeit der englischen Grammatik. Ein Angestellter ist keine besondere Art von Person, sondern eine Rolle, die eine Person haben kann. Es ist tatsächlich eine Has-a-Beziehung. –

3

Nein, das geht nicht. Alternativ können Sie einen Konvertierungskonstruktor in der Zielklasse erstellen (nicht in Ihrem Fall, da Sie ihn in std :: string konvertieren möchten - sofern Sie ihn nicht ableiten). Aber ich stimme den anderen Antworten zu, ich denke, eine implizite Konvertierung wird in diesem Fall nicht empfohlen - besonders, weil Sie nicht von einem Objekt, sondern von einem Zeiger konvertieren. Besser, eine freie Funktion zu haben, wird Ihr Code einfacher zu verstehen sein und der nächste Programmierer, der den Code erbt, wird Ihnen sicher danken.