2009-02-17 6 views
5

lorsque vous faitesConstructor ne fonctionne pas pour la classe héritée de std :: string

#include <string> 

class MyString : public std::string 
{ 
public:  
    MyString() {} 
}; 

Mais l'utilisation ci-dessous:

MyString s = "Happy day"; 
MyString s("Happy Day"); 
MyString s = (MyString)"Happy day"; 

aucun d'eux fonctionne.

Il semble qu'il y ait quelque chose à faire avec les constructeurs/opérateurs de déclaration/dépassement de capacité, mais est-ce que quelqu'un peut aider à indiquer où trouver ces ressources?

Merci.

+0

Lorsque vous héritez, vous masquez les opérateurs non-par défaut de la classe de base. Si vous voulez appeler ces constructeurs, vous devez définir des contructeurs non-par défaut dans votre sous-classe qui les invoquent. – ChrisW

+1

Vous n'êtes pas censé hériter de std :: string. Vous pouvez le dire par le fait qu'il n'a pas de destructeur virtuel. Vous vous ouvrez à beaucoup de problèmes potentiels. Rendre std :: string un membre. –

Répondre

6

Vous devez définir certains constructeurs pour les différents types que vous voulez être en mesure de convertir vos chaînes en. Ces constructeurs peuvent simplement transmettre les paramètres au sous-jacent std::string.

Si vous ne créez pas manuellement eux, le compilateur crée un défaut- et une copie-constructeur pour vous:

MyString() : std::string() { } 
MyString(const MyString &other) : std::string(other) { } 

Pour permettre la construction de chaînes littérales, vous avez besoin d'un constructeur qui prend un const char*:

MyString(const char* other) : std::string(other) { } 

un constructeur qui prend const std::string& serait également utile pour convertir std::string s à votre type de chaîne. Si vous voulez éviter les conversions implicites des chaînes normales, vous devriez en faire explicit:

explicit MyString(const std::string &other) : std::string(other) { } 

(Edité parce que ma version originale était pleine d'erreurs et je ne peux pas supprimer la réponse acceptée)

+0

Merci d'avoir fourni le constructeur de copie. – purga

+0

Je ne vois pas la différence entre 'MyString s ("Happy Day")' et 'MyString s ("abc")'. Vous vous trompez sûrement. –

+0

Gardez à l'esprit que cela permet au compilateur de substituer MyString à std :: string lors de la résolution de surcharges, etc.Cela peut être ce que vous voulez, ou conduire à une confusion horrible. J'ai vu les deux cas. –

1

Vous définissez un ctor MyString qui ne prend pas d'arguments. Si elle remplace les autres cteurs, il n'y a pas de ctor qui prenne un argument de chaîne.

Vous devez cteur d'un argument de type const char *, quelque chose comme

MyString(const char * s): std::string(s){} 

(Ne vous fiez pas la syntaxe, regardez vers le haut, je ne vous écris pas C++ chaque jour plus longtemps.)

Vérifiez la section dans C++ FAQ Lite on ctors.

(Oops. Const char *, pas de chaîne. Je vous avais dit que je n'ai pas écrit C++ chaque jour.)

3

Le problème est que vous devez surcharger le constructeur qui prend const char * et appeler la classe de base Constructeur comme suit:

class MyString : public std::string { 
    public:  
     MyString() {} 
     MyString(const char* c) : std::string(c) {} 
}; 

Vos trois tests devraient alors fonctionner. Std :: string n'est pas destiné à être hérité de

3

. Il n'a aucune méthode virtuelle, donc vous ne pouvez pas remplacer n'importe laquelle de ses méthodes.

Vous devriez vous pencher sur la composition. Ou simplement créer des fonctions utilitaires qui fonctionnent sur des chaînes std ::

34

std::string n'est pas conçu pour l'héritage. Il n'a pas aucune fonction virtuelle (pas même le destructeur!), Donc vous ne pouvez rien changer. Il n'a pas non plus d'interface protégée, donc vous ne gagnez rien de la sous-classe que vous ne pourriez pas obtenir en créant des fonctions utilitaires autonomes qui prennent std::string. Gardez à l'esprit que la plupart des implémentations STL s'attendent à utiliser std::string avec une sémantique de copie et non une sémantique de référence, ce qui rend l'ajout de champs hérités ou de fonctions de substitution encore plus faible.

Si vous vraiment voulez quelque chose comme std::string avec des fonctions supplémentaires, vous pourriez envisager d'utiliser la composition au lieu de l'héritage, mais ce n'est pas génial non plus. Vous n'avez pas à vous inquiéter du fait que le destructeur std::string ne soit pas appelé correctement, mais vous finissez par avoir à emballer beaucoup de méthodes de std::string dont vous avez besoin, ce qui est fastidieux. De plus, vos fonctions utilitaires ne fonctionneront qu'avec MyString alors que la plupart des codes vont s'attendre à std::string, donc ce n'est pas très réutilisable.

Vous feriez mieux de faire quelques fonctions utilitaires qui prennent std::string.Ou, si std::string ne fournit pas ce dont vous avez besoin, vous devriez opter pour une autre implémentation de chaîne adaptée à vos besoins. Voici quelques possibilités qui vous viennent à l'esprit:

+0

Bien sûr, vous pouvez en hériter. Vous devez juste vous assurer que son résolvable à la compilation. –

+0

Je ne vous ai pas dit ** ne pouvait pas ** en hériter. Juste que vous gagnez peu en le faisant. – tgamblin

+0

@Charlie: tu * peux *, ça ne t'achète rien puisque tu ne peux rien surcharger. Vous feriez mieux de faire des fonctions utilitaires qui utilisent les méthodes de std :: string. –

4

Le fond ligne est que vous ne devriez pas faire cela. Le destructeur sur std::string n'est pas virtuel. Cela signifie que si vous effectuez les opérations suivantes:

std::vector<std::string*> s_vector; 
s_vector.push_back(new MyString("Hello")); 
s_vector.push_back(new std::string("World")); 

const std::vector<std::string*>::iterator s_vector_end = s_vector.end(); 
std::vector<std::string*>::iterator s = s_vector.begin(); 
for (; s != s_vector_end; ++s) 
{ 
    delete *s; // Error, MyString's destructor will 
       // not be called, but std::string's! 
} 

La seule façon que cela pourrait être en sécurité est si vous ne pas ajouter des membres à votre chaîne. Vous pourriez penser que vous n'en avez pas besoin maintenant, mais quelqu'un qui n'est pas au courant de ces problèmes peut venir plus tard (ou vous, quand vous avez peut-être oublié ce conseil) et en ajouter un, et hop, vous avez un difficile de traquer les fuites de mémoire.