Maintant vu le code, la solution pourrait etre open() tout simplement. Mais ... pourquoi cette surcouche? C'est une idée de prof?
Rien, que l'invariant dynamique me hérisse le poil. Pourquoi avoir une fonction de lecture sur des flux qui peuvent se manipuler en écriture et rejeter si le le mode d'ouverture ne correspond pas? Keep It Simple (and Stupid). C'est comme avoir une fonction pédaler sur un véhicule pour se prendre une exception quand en fait on a un camion...
> goto error;
Mais non! Throw direct! Voyons. Quelle idée. Tu es en C++ maintenant, oublie tout ce que tu as appris ailleurs.
mon example ne correspond pas à mon code, et je veux juste savoir la question qui est dans le titre . Mon code est sans doute horrible mais ifstream::open ne correspond pas à ce que je veux faire .
PS: je modiferais des petites choses y compris le mode
mon example ne correspond pas à mon code, et je veux juste savoir la question qui est dans le titre . Mon code est sans doute horrible mais ifstream::open ne correspond pas à ce que je veux faire
Ta question est bien : comment initialiser un objet ifstream ou ofstream?
Deux manières existent qui sont exactement la réponse à ta question. - n = std::ifstream("filename.ext"); mais ça ne fonctionne qu'à partir du C++11. - n.open("filename.ext"); qui marche depuis très longtemps.
Si j'ai bien compris tu souhaites la réponse à ta question mais tu ne veux pas que ça soit open() et tu n'as pas le C++11. Je pense que l'on est bien au-delà du problème XY.
Déjà, pourquoi vourais tu pouvoir avoir une classe qui contienne à la fois un flux en entrée et un flux en sortie?
Soit, tu veux extraire certaines données de ton flux, et tu l'ouvre en entrée (ifstream), soit, tu veux y injecter des données, et tu l'ouvre en sortie (ofstream)
Ensuite, pourquoi voudrais tu garder ce flux (d'entré OU de sortie selon le cas) ouvert en permanence?
Il faut, en effet, savoir que le système d'exploitation va -- typiquement -- poser un "verrou" sur les fichiers qui sont ouverts (que ce soit en lecture ou en écriture) de manière à éviter que deux applications différentes n'essayent d'y accéder en même temps (que ce soit l'une en écriture pendant que l'autre le modifie, les deux pour le modifier ou même les deux en lecture).
Dés lors, il est souvent préférable (en fonction de l'usage auquel tu destine ton flux bien sur) de n'ouvrir ton flux que le temps nécessaire à y faire ce que tu veux faire dedans (en essayant, autant que possible, de regrouper un maximum de choses à faire) et de le refermer dés que ce qu'il y a à faire est terminé.
Pour y arriver "relativement" facilement, tu dois absolument essayer de comprendre et d'appliquer trois principes de base (qui te seront très utiles dans bien d'autres circonstances):
le sempiternel SRP (Single Responsability Principle ou principe de la responsabilité unique, le S de SOLID): chaque donnée, chaque type de donnée, chaque fonction ne doit faire qu'une seule chose, mais doit la faire correctement: plutot que d'avoir une classe OPEN, tu devrais plutôt envisager -- si tu tiens à travailler avec des classes -- la création d'une classe Loader (ou Reader, si tu préfères) qui se chargera de charger les informations et d'une classe Writer (ou Saver) qui se chargera de l'écriture (mais des fonctions libres iraient aussi très bien )
La non moins sempiternelle loi de Déméter: l'utilisateur n'a pas à savoir que tes classes Loader et Saver (ou Reader et Writer) utilisent explicitement des flux en interne. Tout ce qu'il doit savoiir à leur sujet, c'est qu'elles sont destinées à fournir des services bien particuliers (leur nom nous donne une vague idée des services que l'on peut en attendre) et qu'elles ont besoins d'une chaine de caractères représentant le nom du fichier à utiliser (*).
le DIP (Dependancy Inversion Principle ou principe d'inversion des dépendances; le D de SOLID); auquel on fait sans doute moins souvent référence: il est souvent plus facile de s'assurer qu'une donnée soit transmise par paramètre à une fonction que de forcer cette donnée à être une donnée membre (un "attribut") de la classe.
Ainsi, si tu tiens vraiment à travailler avec des classes, la classe Reader (tu lui donnes, bien sur, le nom que tu veux) pourrait ressembler à quelque chose comme
class Reader{
public:
/* il faut donner le nom du fichier qui sera lu par l'instance
* de la classe, et c'est en gros la seule information
* qui soit absolument spécifique à toutes les instances
*/
Reader(std::string const & filename):filename_{filename}{
}
/* l'utilisateur voudra obtenir un "ensemble de données
* à la lecture du fichier
*/
AllDatas read(){
// on crée la donnée
// et on l'initialise tout de suite dans la foulée
std::ifstream ifs{filename_};
if(! ifs){
// si, pour une raison ou une autre, on n'arrive
// pas à ouvrir le fichier, ca ne sert à rien
// d'aller plus loin
throw std::runtime_error("unable to open file");
}
// si on arrive ici, c'est que l'ouverture s'est bien
// passée
/* tout ce qu'il faut faire pour exécuter la lecture
*/
/* on va créer la donnée qui sera mise à jour */
AllData ad;
/* on appelle une fonction qui s'occupe de la lecture
* proprement dite en lui fournissant le flux et
* la donnée à mettre à jour
*/
read(ifs, ad):
return ad;
}
private:
/* la fonction qui va effectivement s'occuper de
* la lecture (inaccessible à l'utilisateur)
*/
void read(std::isteam & ifs, AllData & ad){
/* ca, c'est ton job */
}
/* le nom du fichier qui devra être utilisé */
std::string filename_;
};
Ta classe Writer sera sensiblement identique, à ceci près que tu devras transmettre la donnée que tu veux faire enregistrer. Elle ressemblera donc à quelque chose comme
class Writer{
public:
Writer(std::string const & filename):filename_{filenmae}{
}
void write(AllData const & ad){
/* on ouvre le fichier, on lance une exception
* si cela échoue
*/
std::ofsteam ofs{filename_};
if(! ofs)
throw std::runtime_error("unable to open file");
write(ofs, ad);
}
private:
void write(std::ostream & ofs, AllDatas const & ad){
/* ca, c'est ton job */
}
std::string filename_;
};
Et je le rappelle: on pourrait parfaitement faire cela sous la forme de fonctions libres -- éventuellement dans un espace de noms (grâce au respect du DIP) en exposant deux fonctions proches de
namespace MonEspaceDeNoms{
/* ca, ce sont les fonctions dont l'utilisateur a connaissance
*/
AllData read(std::string const & filename);
void write(std::string const & filname, AllData const & ad);
}
/* et les fonctions qui nous amènent au résultat */
namespace MonEspaceDeNoms{
void read(std::istream & ifs, AllData & ad){
/* ca, c'est ton job */
}
void write(std::ostream & ifs, AllData const & ad){
/* ca, c'est ton job */
}
/* l'implémentation des fonctions dont l'utilisateur a connaissance
*/
AllData read(std::string const & filneame){
/* juste une adaptation de ce que l'on a fait
* pour la classe Reader
*/
std:ifstream ifs{filename};
if(!ifs)
throw std::runtime_error("Unable to open file");:
AllData ad;
read(ifs, ad);
return ad;
}
void write(std::string const & filneame, AllDatas const & ad){
/* juste une adaptation de ce que l'on a fait
* pour la classe Writer
*/
std:ofstream ofs{filename};
if(!ifs)
throw std::runtime_error("Unable to open file");
write(ofs, ad);
}
}
Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
comment initialiser un objet ifstream ou ofstream
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
En recherche d'emploi.