IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Probleme de cast en constructeur copy.


Sujet :

C++

  1. #1
    Membre averti
    Inscrit en
    Août 2006
    Messages
    18
    Détails du profil
    Informations forums :
    Inscription : Août 2006
    Messages : 18
    Par défaut Probleme de cast en constructeur copy.
    Bonjour à toutes et à tous!

    Voilà, j'ai un souci avec un de mes dev.
    Je résume rapidement en simplifiant un max.
    J'ai une classe de base nomée IOBject. Cette classe ne fais pas grand chose, joue juste le rôle d'interface:
    ( Edité après que j'ai vu que les tabs ont complètement ravagé le code ^^, et ajout de GetContent pour que vous voyez la méthode.)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    class IObject {
    public:
    	virtual char* ToString (void) const { return "IObject"; };
    	virtual		~IObject () {};
    };
    Ensuite, j'ai une classe dérivée CHString qui hérite de IObject. voici les infos importantes pour la compréhension de mon problème:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
     
    // __ctors
    CHString::CHString() : szContent(NULL) {
    	SetContent("");
    }
    CHString::CHString(const char* szInit) : szContent(NULL) {
    	if (szInit!=szContent)
    		SetContent(szInit);
    }
    CHString::CHString(const IObject& cInit) : szContent(NULL) {
    	if (&cInit!=this)
    		SetContent(cInit.ToString());
    }
     
    // IObject virtual implementation
    char* CHString::ToString(void) const {
    	return GetContent();
    }
     
    // Getter on the String's content...
    char* CHString::GetContent() const {
    	return szContent;
    }
    // Set the String content...
    void CHString::SetContent(const char* szNewContent) {
    	ReallocContent(strlen(szNewContent));
    	strcpy(szContent, szNewContent);
    }
    // Frees the memory used by the content.
    void CHString::FreeContent() {
    	if (szContent!=NULL)
    		delete [] szContent;
    }
    // Changes the size of the allocated content.
    void CHString::ReallocContent(size_t iNewLength) {
    	try {
    		FreeContent();
    		szContent	= new char[iNewLength+1];
    	} catch (...) {
    		throw CMemoryErrorEx("Unable to allocate data for a CHString object.", __FILE__, __LINE__);
    	}
    }
    NOTEZ BIEN que le type d'objet requis en 2e constructeur est "IObject"...

    Ensuite, dans mon prog, disons que je fasse ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    CHString	sTestStr1("Test");		// Ca passe...
    CHString	sTestStr2(sTestStr1);		// Crash!
    CHString	sTestStr3	= sTestStr2;	// Crash!
    Les crash sonts soit disant provoqués par "Exception: User breakpoint.", même quand il n'y a pas de breakpoints.
    Notez, qu'après debug du truc, la première instanciation appelle le 2e constructeur. Les deux autres n'appellent AUCUN constructeur

    J'ai tenté un changement qui résoud le problème, mais du coup mon programme ne pourra pas fonctionner pour ce que je veux en faire: j'ai changé le type d'objet requis en constructeur 2 pour un "CHString". Et là ça passe, les deux appels se fonts par ce constructeur...

    Si quelqu'un a une idée, je suis prenneur ^^

    Merci!
    Pierrot.

  2. #2
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 393
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 393
    Par défaut
    1. Regarde ton premier post et tu verras les ravages de l'indentation intermédiaire par des tabs. Les tabs, c'est uniquement en début de ligne.
    2. Fais retourner un char const * à ToString() : Je suis surpris que ça compile pour l'instant...
    3. Tu ne nous montre pas le code de GetContent()...
    4. CHString hérite bien de IObject ?
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Membre averti
    Inscrit en
    Août 2006
    Messages
    18
    Détails du profil
    Informations forums :
    Inscription : Août 2006
    Messages : 18
    Par défaut Modification faites.
    Merci pour ta réponse,

    J'ai changé le premier post, désolé pour le formatage.
    CHString hérite bien de IObject, peut être pas de la bonne façon?:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    class CHString	: public IObject {
    [...]
    };
    Concernant le char* const ToString() à la place du char* ToString() const, ça ne fonctionne pas... cv-qualifiers bien sûr:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    Error: the object has cv-qualifiers that are not compatible with the member function
    C'est voulu pour le char* ToString const ^^.

    Note: J'ai essayé en mettant la variable szContent en public et en private, cela ne change rien...

    Merci de votre aide!
    Pierrot.

  4. #4
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 393
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 393
    Par défaut
    Si tu exécutes entièrement en Debug ("Start debugging") et que tu remontes un petit peu la pile d'appel ("Call Stack"), tu pourras sans doute voir où ça plante précisément dans le constructeur...

    Et si, tu peux mettre const partout, sauf si tu utilises le retour de ToString() avec une fonction qui exige une chaîne modifiable, sans qu'on sache pourquoi (mais ce serait une mauvaise raison car les chaînes que tu retournes sont non-modifiables de toute façon).
    Edit: On s'est mal compris. En fait, je conseillais char const * ToString() const...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  5. #5
    Membre averti
    Inscrit en
    Août 2006
    Messages
    18
    Détails du profil
    Informations forums :
    Inscription : Août 2006
    Messages : 18
    Par défaut Précisions...
    Bon j'ai dû mal m'exprimer.

    Ca ne plante pas au moment du constructeur, car (ne me dites pas c'est pas vrai, moi non plus j'y crois pas) AUCUN constructeur n'est appellé quand l'objet requis est de type IObject. Le bug apparrait à la fin de ma fonction principale, au moment où les destructeurs sont appellés. Le cas 1 fonctionne, et est détruit. Les deux autres non, le destructeur plante, et je n'arrive pas à localiser quoi que ce soit de pertinent en pile.

    Concernant les consts, je vais tester en char const * ToString() const. Tu m'expliques la différence profonde?
    Edit: Je viens de passer en "char* const CHString::ToString(void) const". Ca compile, le bug est toujours là. Selon toi il faudrait que je change partout? oO

    Merci beaucoup!
    Pierrot.

  6. #6
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 393
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 393
    Par défaut
    La différence profonde, c'est que là, on ne pourra VRAIMENT pas tenter de modifier la chaîne retournée (parce que si on tente d'écrire à l'adresse retournée par IObject::ToString(), on aura une belle Access Violation sous Windows, un belle segfault sous Linux.
    (Un de mes plus grands reproches à Visual C++ est qu'il ne semble pas avoir d'option équivalente au paramètre -Wwrite-strings de GCC).


    En fait, pour le coup du constructeur de copie, je crois que j'ai trouvé l'origine du bug: Ce constructeur n'est PAS un constructeur de copie! C'est un constructeur de conversion pour tout ce qui hérite de IObject.

    Ainsi, lorsque le compilo tombe sur tes deux instanciations, il appelle le constructeur de copie par défaut au lieu d'appeler ton constructeur: La bête copie membre à membre.
    Résultat, les destructeurs tentent de désallouer deux fois la même zone.

    -->Donc, pour corriger, il faut que tu fasses ton constructeur de copie spécifique à CHString, qui fera la même chose que ton constructeur à partir de IObject.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  7. #7
    Membre averti
    Inscrit en
    Août 2006
    Messages
    18
    Détails du profil
    Informations forums :
    Inscription : Août 2006
    Messages : 18
    Par défaut Oula!
    Tu veux dire qu'il faut dans CHString un constructeur qui requiert un IObject, un autre qui requiert un CHString?!

    Mais là ça fout en l'air tout mon truc. Je m'ezplique ^^
    Le but de la manoeuvre c'est d'avoir, grace à IObject, l'assurance que tous les objets en étant dérivés comportent la méthode ToString. De cette façon, peut importe l'objet qu'on passe à la classe CHString (ou CHInt ou CHWhateverUWant), le constructeur de CHString initialiserait son contenu grace à la méthode générique... Le but étant bien sûr que si je développe une classe CHFloat, je puisse la passer en param au constructeur de CHString SANS avoir à ajouter un constructeur dans CHString. Ca s'appelle pas le polymorphisme? Je sais plus ^^ Peut être le transtypage?

    Le meilleur exemple pour ça est le tuto qu'avait fait Laurent Gomila, on a une classe ILogger avec deux trois méthodes virtual, ensuite on en dérive par exemple une classe CLoggerFile et on peut ensuite s'ammuser à faire ILogger::SetInstance(new CLoggerFile("Debug.txt"));. Et du coup pour loguer on a plus qu'à faire: ILogger::Log("Ce qu'on veut"). La classe ILogger prend en paramètre une instance de ILogger! Et vu que ses méthodes sont virtual pour la plupart, elles appellent bien dans CLoggerFile qui les implémente.

    Vouala ce que je cherche à faire ^^ C'est juste que je ne comprend pas pourquoi ça ne fonctionne pas, ça devrait pourtant

    Merci!
    Pierrot.

  8. #8
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 393
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 393
    Par défaut
    Le constructeur de copie est un cas particulier. Il te faut donc un constructeur pour n'importe quel IObject, et un constructeur de copie (que tu peux rendre private si tu veux interdire la copie de CHString).
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  9. #9
    Membre averti
    Inscrit en
    Août 2006
    Messages
    18
    Détails du profil
    Informations forums :
    Inscription : Août 2006
    Messages : 18
    Par défaut Donc...
    Donc, à quoi ressemblerait le constructeur pour "n'importe quel IObject"? Je pensais que c'est ce que j'avais fait...

  10. #10
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 393
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 393
    Par défaut
    Oui, c'est bien celui-ci.

    Mais tu dois ajouter un vrai constructeur de copie qui fera la même chose.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  11. #11
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 287
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 287
    Par défaut
    Citation Envoyé par hickscorp
    CHString hérite bien de IObject, peut être pas de la bonne façon?:
    Si c'est ça la question, c'est un très mauvais choix de design. On le rencontre généralement dans les langages où l'abscence de généricité afaiblit le typage. Perso, entre un type Object duquel tout le monde dérive et un void*, je ne vois aucune différence.

    Dans les effets de bords, autre que la perte d'un typage fort, bonne chance pour implémenter une sémantique de valeur (et en particulier de copie! (ou comment revenir au thème initial)) sur ta classe de chaînes. C'est pas que cela soit impossible ... c'est juste que tu auras de la gymnastique inutilement compliquée qui ne te rendra même pas un typage fort.

    Au fait. Pourquoi réinventer la roue ?
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  12. #12
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 393
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 393
    Par défaut
    C'est vrai que le coup du IObject, là, il faudrait plutôt lui donner un nom du genre IConvertibleToString...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  13. #13
    Membre averti
    Inscrit en
    Août 2006
    Messages
    18
    Détails du profil
    Informations forums :
    Inscription : Août 2006
    Messages : 18
    Par défaut Oula! ^^
    Bon merci pour ces réponses, effectivement le ICharArrayExportable est une bien meilleure idée que le IObject... Seulement voilà, le IObject ne contient pas que ça ^^

    Ya pas mal d'autres méthodes que je ne m'amuserais pas à poster ici, mais histoire de se faire une idée et entre autres, une persistence BDD... Un objet peut avoir plusieurs états: Abstract, Up-To-Date, Deleted, Modified. Ensuite des méthodes statiques s'occupent de le maintenir en base...

    Bref, je vais revoir mon design, je pense avoir trop essayé de m'approcher de java sur ce coup ^^

    En tout cas, merci pour vos réponses, problème résolu.
    Pierrot.

  14. #14
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 393
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 393
    Par défaut
    Mon conseil: Tu multiplies les interfaces, et tu peux même faire de l'héritage d'interfaces, jusqu'à trouver l'ensemble qui te convient.
    Et ensuite, tu pourras te préoccuper des objets eux-mêmes.

    De plus, je te conseille de ne proposer en plus des classes abstraites mères, des classes d'objets à inclure directement pour implémenter certaines interfaces (cela t'évitera d'avoir à faire de l'héritage multiple de classes contenant des données, ce qui sera plus proche de Java et de .Net.)
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 4
    Dernier message: 16/11/2005, 11h22
  2. Réponses: 12
    Dernier message: 25/07/2005, 14h49
  3. [VB.NET][dataset][datagrid] probleme de Cast
    Par graphicsxp dans le forum Windows Forms
    Réponses: 3
    Dernier message: 05/05/2005, 14h18
  4. Probleme de cast de parametres
    Par John Fullspeed dans le forum Langage
    Réponses: 3
    Dernier message: 14/10/2004, 08h43
  5. probleme de cast
    Par gaut dans le forum C++
    Réponses: 9
    Dernier message: 06/08/2004, 18h43

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo