2009-10-24 26 views
5

En C++ est-il possible de définir des opérateurs de conversion qui ne sont pas des membres de classe? Je sais comment faire pour les opérateurs réguliers (tels que +), mais pas pour les opérateurs de conversion.Opérateurs de conversion C++ définis par l'utilisateur sans classes?

Voici mon cas d'utilisation: Je travaille avec une bibliothèque C qui me distribue un PA_Unichar *, où la bibliothèque définit PA_Unichar comme un int 16 bits. C'est en fait une chaîne codée en UTF-16. Je veux le convertir en un std::string codé en UTF-8. J'ai tout le code de conversion prêt et de travail, et je ne manque que le sucre syntaxique qui me permettrait d'écrire:

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

(habituellement dans une ligne sans la variable temp).

A noter également:

  • Je sais que std::string ne définit pas la conversion implicite de char* et je sais pourquoi. La même raison pourrait s'appliquer ici, mais ce n'est pas la question. J'ai une ustring, sous-classe std::string qui définit l'opérateur de conversion correct à partir de PA_Unichar*. Cela fonctionne mais cela signifie utiliser ustring variables au lieu de std::string et que puis nécessite la conversion à std::string lorsque j'utilise ces chaînes avec d'autres bibliothèques. Cela n'aide pas beaucoup. L'utilisation d'un opérateur d'assignation ne fonctionne pas car les doivent être des membres de la classe.

est-il donc possible de définir des opérateurs de conversion implicite entre deux types que vous ne contrôlez pas (dans mon cas PA_Unichar* et std::string), qui peuvent ou peuvent ne pas être les types de classe?

Si ce n'est pas ce qui pourrait être des solutions de contournement?

Répondre

8

Qu'est-ce qui ne va pas avec une fonction gratuite?

std::string convert(PA_Unichar *libOutput); 

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

Modifier réponse au commentaire:

Comme DrPizza says: Tout le monde tente de boucher les trous ouverts par les conversions implicites par les remplaçant par ceux conversion explicite que vous appelez « l'encombrement visuel ».

En ce qui concerne la chaîne temporaire: Attendez simplement la prochaine version du compilateur. Il est susceptible de venir avec des références rvalue et son implémentation std::string implémentera la sémantique de déplacement en plus de cela, ce qui élimine la copie. Je n'ai pas encore vu un moyen moins cher d'accélérer votre code que de simplement passer à une nouvelle version du compilateur.

+0

Qu'est-ce qui ne va pas? Pas grand-chose, mais quand même, deux choses: - l'encombrement visuel, quand vous avez des centaines d'appels sans signification à convertir - cette solution implique l'utilisation d'une chaîne temporaire std :: string. Cela signifie que les données sont copiées deux fois, tout le temps. Cela peut ou peut ne pas être un problème, mais n'est pas très satisfaisant. –

+6

La plupart des compilateurs optimiseront la copie supplémentaire. – rlbond

+4

jdmuys> rlbond a raison, RVO est commun et réel dans la pratique. Vous pourriez vouloir lire ceci: http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/ – Klaim

4

Je ne pense pas que vous puissiez définir des opérateurs de conversion "globaux". Les normes disent que conversion functions sont special member functions. Je propse ce qui suit si je pouvais considérer le sucre syntaxe suivante:

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... 
    } 
}; 

Soyez conscient que le comportement polymorphique de cette classe est brisée.Tant que vous n'en créez pas un objet via un pointeur de type string*, vous êtes dans le coffre-fort! Donc, ce code est parfait:

mystring str(....); 

Comme dit précédemment, le code suivant est cassé!

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

Les conversions implicites sont le diable, de toute façon. Rendez-le explicite avec un appel de fonction de conversion.

+4

Eh bien, ça dépend. Il existe des situations réelles où les conversions implicites ont du sens. Je les utilise typiquement, par exemple, pour convertir un type en un autre qui est, en termes sémantiques, un sous-ensemble de l'autre. Si vous avez une classe «personne» et un «employé», par exemple, je m'attendrais à ce que «employee» se convertisse automatiquement en «personne» partout où l'on s'attend à ce que ce soit le cas. (Bien sûr, la conversion implicite de l'inverse serait une mauvaise idée, d'un autre côté.) – Mephane

+1

Je réalise que vous venez de proposer un exemple hypothétique, mais employé comme une sous-classe de personne est un mauvais design et une bête noire de mien. Le sous-classement est utilisé pour une relation is-a. Il semble qu'un employé est une personne, mais en fait cela fait partie de l'ambiguïté de la grammaire anglaise. Un employé n'est pas un type spécial de personne, mais plutôt un rôle qu'une personne peut avoir. C'est en fait une relation has-a. –

3

Non, vous ne pouvez pas. Ce que vous pourriez faire comme alternative est de créer un constructeur de conversion dans la classe cible (pas votre cas, comme vous voulez le convertir en std :: string - sauf si vous le dérivez). Mais je suis d'accord avec les autres réponses, je pense qu'une conversion implicite n'est pas recommandée dans ce cas - surtout parce que vous ne convertissez pas d'un objet mais d'un pointeur. Mieux vaut avoir une fonction gratuite, votre code sera plus facile à comprendre et le prochain programmeur à hériter du code vous en sera certainement reconnaissant.