Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 24/12/2011, à 17:37

C'est Moi

C++ problème d'héritage de classe contenant un ofstream (débutant)

salut à tous
petite question : j'ai deux classes

class A{
public:
A(string nom):file_(nom.c_str(),ios::out | ios::trunc){}
protected:
ofstream file;
}

et

class B: public A{
B(A a):A(a){}
}

chaque classe est fonctionnelle si je ne déclare pas d'attribut "ofstream file", mais si je compile le tout je recois une erreure du genre :

/usr/include/c++/4.4/bits/ios_base.h: In copy constructor ‘std::basic_ios<char, std::char_traits<char> >::basic_ios(const std::basic_ios<char, std::char_traits<char> >&)’:
/usr/include/c++/4.4/bits/ios_base.h:790: error: ‘std::ios_base::ios_base(const std::ios_base&)’ is private

je suis sur que c'est une erreur très bête mais je ne vois vraiment pas... merci de m'aider !
bon noel!!!

Dernière modification par C'est Moi (Le 24/12/2011, à 17:44)

Hors ligne

#2 Le 25/12/2011, à 22:38

pingouinux

Re : C++ problème d'héritage de classe contenant un ofstream (débutant)

Bonsoir,
Pour obtenir de l'aide, ce serait bien de fournir le programme, ou au moins la partie qui permet de reproduire le message d'erreur.

Hors ligne

#3 Le 26/12/2011, à 13:22

omc

Re : C++ problème d'héritage de classe contenant un ofstream (débutant)

Bonjour,
Déjà, tu as dût faire une erreur de copié/collé, la déclaration de ta classe A devrait être :

class A{
public:
A(string nom):file_(nom.c_str(),ios::out | ios::trunc){}
protected:
ofstream file_;
}

file avec un underscore : file_.
Sinon pour ton erreur, le compilo te donne toutes les infos :

/usr/include/c++/4.4/bits/ios_base.h: In copy constructor ‘std::basic_ios<char, std::char_traits<char> >::basic_ios(const std::basic_ios<char, std::char_traits<char> >&)’:
/usr/include/c++/4.4/bits/ios_base.h:790: error: ‘std::ios_base::ios_base(const std::ios_base&)’ is private

A un certain moment de ton programme tu instancies le constructeur par copie de "ofstream" (or celui-ci est privé). Après la bonne question est quand ?
Certainement, tu dois invoquer de façon explicite ou implicite le constructeur par copie de A ou B et que celui-ci invoque à son tour le constructeur par copie de ofstream.
Pour éviter ce problème, tu ne dois pas laisser le compilo définir le constructeur par copie de ta classe A et B.

Pour ce faire, tu dois toi même définir-déclarer le constructeur par copie, et lui donner une signification cohérente :

class A{
public:
A(string nom):file_(nom.c_str(),ios::out | ios::trunc){}
A(const A& a):file_//Je te laisse faire la suite.
protected:
ofstream file_;
}

Bon courage, (et non ce n'est pas une erreur vraiment évidente).

PS:
Il faut également se poser des questions de conception :
Est-ce légitime de faire une copie de A ?

Dernière modification par omc (Le 26/12/2011, à 13:28)

Hors ligne

#4 Le 28/12/2011, à 22:56

C'est Moi

Re : C++ problème d'héritage de classe contenant un ofstream (débutant)

hi,

en effet, j'ai fait une erreur de copie déso... mais mon prog est long et je voulais juste synthétiser là où j'ai mon prob !!!

alors oui, je fais une copie implicite de ma classe mais je croyais que par défaut le compilateur me fournit une constructeur de copie... de plus, un pote m'a dit que si je commence à définir une fois un constructeur de copie, je dois tous les définir : en fait ma classe A hérite d'une classe Z qui elle même hérite d'une classe Y... si il faut juste que je définisse le constructeur de la classe A, aucun souci (genre : A(const A &a):file_(a.nom.c_str(), ios::out|ios::trunc){}, en ayant déclaré un attribut string nom à ma classe A), mais sinon jusqu'où je dois remonter?

par aillieur, si à la place de mettre un ofstream je mets un double, je n'ai aucun problème... pourquoi le constructeur de ofstream est privé (question réthorique, je ne pense de toute façon pas comprendre la réponse...)?!

au fait, en quoi ce ne serait pas légitime de faire une copie de A?

merci beaucoup pour vos réps !!!
@+

Dernière modification par C'est Moi (Le 28/12/2011, à 23:00)

Hors ligne

#5 Le 29/12/2011, à 01:52

eiger

Re : C++ problème d'héritage de classe contenant un ofstream (débutant)

C'est Moi a écrit :

alors oui, je fais une copie implicite de ma classe mais je croyais que par défaut le compilateur me fournit une constructeur de copie...

En effet, le compilateur te fournit un constructeur de copie ... ce qui est une source d'erreur très classique, la preuve. Le compilateur va tenter de faire une copie de toutes les variables membres de ta classe, sauf que sur un objet de type ofstream, ça ne marche pas, puisqu'il n'a pas de constructeur de copie ni d'opérateur d'assignation (opérateur = ).

C'est Moi a écrit :

par aillieur, si à la place de mettre un ofstream je mets un double, je n'ai aucun problème... pourquoi le constructeur de ofstream est privé (question réthorique, je ne pense de toute façon pas comprendre la réponse...)?!

Le constructeur de copie est privé, mais c'est juste un moyen technique, cela va bien plus loin que cela. En fait, un ofstream n'a pas de constructeur de copie, ni d'opérateur d'assignation. Si tu regardes toi-même le fichier ios_base.h cité dans l'erreur de GCC, tu verras que ces deux fonctions sont privées, certes, mais surtout n'ont pas de définition. Le nouveau standard C++ précise clairement à l'aide d'un nouveau mot-clé, qu'il s'agit de "deleted definitions" (et du coup, elles ne sont plus privées, mais cela ne change rien). Autrement dit, ces fonctions n'existent pas, donc il est interdit de les appeler.
Pourquoi ? Venons en à la question suivante.

C'est Moi a écrit :

au fait, en quoi ce ne serait pas légitime de faire une copie de A?

Définir une classe, cela exige de se poser un certain nombre de questions, dont celle-ci : "puis-je copier une instance de ma classe ? Est-ce que cela a un sens ?".
Exemple simple pour commencer : tu souhaites appliquer le design pattern singleton  (il ne peut exister qu'une instance d'une certaine classe). Dans ce cas, cela n'a aucun sens de copier un objet, puisque l'on souhaite qu'il n'en existe qu'un seul. Autant s'assurer que personne ne copiera jamais d'objet, par exemple en rendant privés et vides le constructeur de copie et l'opérateur d'assignation. Cela évitera que ton collègue de projet (qui n'a pas forcément tout suivi) essaie un jour de faire une copie. Et cela t'évitera à toi-même quelques erreurs, lorsque tu reprendras ton projet après quelques mois de pause.
Règle de base : le développeur est paresseux. Tout ce que le compilateur peut faire pour toi est bon à prendre. S'il peut s'assurer qu'une classe est utilisée correctement et conformément à ta conception, laisse le faire.

Cas un peu plus complexe, notre ofstream. Supposons un instant que l'on puisse copier un ofstream. Quel devrait être le comportement de la copie ? Devrait-elle agir sur le même fichier que l'original ? On aurait alors deux objets capables d'écrire dans le même fichier, sans aucune synchronisation.
On pourrait aller plus loin en regardant ce qu'il y a à l'intérieur d'un ofstream. Entre autre on y trouve un buffer. Si la copie était possible, ce buffer serait automatiquement partagé entre les deux objets. Et si l'un des deux objets était supprimé, il supprimerait également le buffer, ce qui laisserait l'objet restant sans buffer, plutôt gênant.
Conclusion : une copie de notre ofstream n'est pas viable comme ça.
Donc si une copie n'a pas de sens, autant indiquer clairement que la copie est interdite en supprimant les 2 fonctions susceptibles d'effectuer une copie : le constructeur de copie et l'opérateur d'assignation.

Pour en revenir à ton problème : si tu penses que copier une instance de A a un sens, alors dans quel fichier la copie doit-elle écrire ? Probablement un autre. Dans ce cas, il te faudra définir toi-même un constructeur de copie et un opérateur d'assignation, dans lesquels tu ouvriras un nouveau fichier. Si tu veux absolument que les deux instances écrivent dans le même fichier, ce sera à toi également de le gérer, en passant par ton constructeur de copie.

Dernière modification par eiger (Le 29/12/2011, à 01:53)

Hors ligne