Bonjour a tous
Dans mon projet, je souhaite sauvegarder mes données sous plusieurs
formats.
Pour cela, j'ai décider de dériver plusieurs classes de ofstream (autant
que
de format), et de surcharger l'operator<< pour chacune. Pour les format de
type texte, il n'y a pas de problemes, mais pour les formats binaires, la
seul solution que j'ai trouvé me semble <tres> lourde, voyez plutot :
osMad << static_cast<char> ((rcA.m_value )&0xFF);
osMad << static_cast<char> ((rcA.m_value>> 8)&0xFF);
osMad << static_cast<char> ((rcA.m_value>>16)&0xFF);
osMad << static_cast<char> ((rcA.m_value>>24)&0xFF);
Rassurez moi, y a t il l'équivalent de la fonction C fwrite qui
permettrait
de sauvegarder mes données au format binaires ?
Bonjour a tous
Dans mon projet, je souhaite sauvegarder mes données sous plusieurs
formats.
Pour cela, j'ai décider de dériver plusieurs classes de ofstream (autant
que
de format), et de surcharger l'operator<< pour chacune. Pour les format de
type texte, il n'y a pas de problemes, mais pour les formats binaires, la
seul solution que j'ai trouvé me semble <tres> lourde, voyez plutot :
osMad << static_cast<char> ((rcA.m_value )&0xFF);
osMad << static_cast<char> ((rcA.m_value>> 8)&0xFF);
osMad << static_cast<char> ((rcA.m_value>>16)&0xFF);
osMad << static_cast<char> ((rcA.m_value>>24)&0xFF);
Rassurez moi, y a t il l'équivalent de la fonction C fwrite qui
permettrait
de sauvegarder mes données au format binaires ?
Bonjour a tous
Dans mon projet, je souhaite sauvegarder mes données sous plusieurs
formats.
Pour cela, j'ai décider de dériver plusieurs classes de ofstream (autant
que
de format), et de surcharger l'operator<< pour chacune. Pour les format de
type texte, il n'y a pas de problemes, mais pour les formats binaires, la
seul solution que j'ai trouvé me semble <tres> lourde, voyez plutot :
osMad << static_cast<char> ((rcA.m_value )&0xFF);
osMad << static_cast<char> ((rcA.m_value>> 8)&0xFF);
osMad << static_cast<char> ((rcA.m_value>>16)&0xFF);
osMad << static_cast<char> ((rcA.m_value>>24)&0xFF);
Rassurez moi, y a t il l'équivalent de la fonction C fwrite qui
permettrait
de sauvegarder mes données au format binaires ?
Bonjour a tous
Dans mon projet, je souhaite sauvegarder mes données sous plusieurs
formats.
Pour cela, j'ai décider de dériver plusieurs classes de ofstream (autant
que
de format), et de surcharger l'operator<< pour chacune. Pour les format de
type texte, il n'y a pas de problemes, mais pour les formats binaires, la
seul solution que j'ai trouvé me semble <tres> lourde, voyez plutot :
#include <iostream>
#include <fstream>
using namespace std;
class A
{
public:
A():m_value(77) {}
virtual ~A() {}
public:
int m_value;
};
class oMadStream : public ofstream
{
public:
oMadStream(const char* sTitre)
{
open(sTitre, ios_base::out|ios_base::trunc|ios_base::binary);
}
};
oMadStream& operator<<(oMadStream& osMad, const A& rcA)
{
osMad << "mad";
osMad << static_cast<char> ((rcA.m_value )&0xFF);
osMad << static_cast<char> ((rcA.m_value>> 8)&0xFF);
osMad << static_cast<char> ((rcA.m_value>>16)&0xFF);
osMad << static_cast<char> ((rcA.m_value>>24)&0xFF);
return osMad;
}
ostream& operator<<(ostream& os, const A& rcA)
{
os << "m_value=" << rcA.m_value << endl;
return os;
}
int main(void)
{
A a;
cout << a;
oMadStream mad("test.mad");
if (mad.is_open())
{
mad << a;
mad.close();
}
return 0;
}
Rassurez moi, y a t il l'équivalent de la fonction C fwrite qui
permettrait
de sauvegarder mes données au format binaires ?
Merci
--
Jérémie
Bonjour a tous
Dans mon projet, je souhaite sauvegarder mes données sous plusieurs
formats.
Pour cela, j'ai décider de dériver plusieurs classes de ofstream (autant
que
de format), et de surcharger l'operator<< pour chacune. Pour les format de
type texte, il n'y a pas de problemes, mais pour les formats binaires, la
seul solution que j'ai trouvé me semble <tres> lourde, voyez plutot :
#include <iostream>
#include <fstream>
using namespace std;
class A
{
public:
A():m_value(77) {}
virtual ~A() {}
public:
int m_value;
};
class oMadStream : public ofstream
{
public:
oMadStream(const char* sTitre)
{
open(sTitre, ios_base::out|ios_base::trunc|ios_base::binary);
}
};
oMadStream& operator<<(oMadStream& osMad, const A& rcA)
{
osMad << "mad";
osMad << static_cast<char> ((rcA.m_value )&0xFF);
osMad << static_cast<char> ((rcA.m_value>> 8)&0xFF);
osMad << static_cast<char> ((rcA.m_value>>16)&0xFF);
osMad << static_cast<char> ((rcA.m_value>>24)&0xFF);
return osMad;
}
ostream& operator<<(ostream& os, const A& rcA)
{
os << "m_value=" << rcA.m_value << endl;
return os;
}
int main(void)
{
A a;
cout << a;
oMadStream mad("test.mad");
if (mad.is_open())
{
mad << a;
mad.close();
}
return 0;
}
Rassurez moi, y a t il l'équivalent de la fonction C fwrite qui
permettrait
de sauvegarder mes données au format binaires ?
Merci
--
Jérémie
Bonjour a tous
Dans mon projet, je souhaite sauvegarder mes données sous plusieurs
formats.
Pour cela, j'ai décider de dériver plusieurs classes de ofstream (autant
que
de format), et de surcharger l'operator<< pour chacune. Pour les format de
type texte, il n'y a pas de problemes, mais pour les formats binaires, la
seul solution que j'ai trouvé me semble <tres> lourde, voyez plutot :
#include <iostream>
#include <fstream>
using namespace std;
class A
{
public:
A():m_value(77) {}
virtual ~A() {}
public:
int m_value;
};
class oMadStream : public ofstream
{
public:
oMadStream(const char* sTitre)
{
open(sTitre, ios_base::out|ios_base::trunc|ios_base::binary);
}
};
oMadStream& operator<<(oMadStream& osMad, const A& rcA)
{
osMad << "mad";
osMad << static_cast<char> ((rcA.m_value )&0xFF);
osMad << static_cast<char> ((rcA.m_value>> 8)&0xFF);
osMad << static_cast<char> ((rcA.m_value>>16)&0xFF);
osMad << static_cast<char> ((rcA.m_value>>24)&0xFF);
return osMad;
}
ostream& operator<<(ostream& os, const A& rcA)
{
os << "m_value=" << rcA.m_value << endl;
return os;
}
int main(void)
{
A a;
cout << a;
oMadStream mad("test.mad");
if (mad.is_open())
{
mad << a;
mad.close();
}
return 0;
}
Rassurez moi, y a t il l'équivalent de la fonction C fwrite qui
permettrait
de sauvegarder mes données au format binaires ?
Merci
--
Jérémie
oMadStream& operator<<(oMadStream& osMad, const A& rcA)
{
osMad << "mad";
osMad << static_cast<char> ((rcA.m_value )&0xFF);
osMad << static_cast<char> ((rcA.m_value>> 8)&0xFF);
osMad << static_cast<char> ((rcA.m_value>>16)&0xFF);
osMad << static_cast<char> ((rcA.m_value>>24)&0xFF);
return osMad;
}
Rassurez moi, y a t il l'équivalent de la fonction C fwrite qui permettrait
de sauvegarder mes données au format binaires ?
Merci
oMadStream& operator<<(oMadStream& osMad, const A& rcA)
{
osMad << "mad";
osMad << static_cast<char> ((rcA.m_value )&0xFF);
osMad << static_cast<char> ((rcA.m_value>> 8)&0xFF);
osMad << static_cast<char> ((rcA.m_value>>16)&0xFF);
osMad << static_cast<char> ((rcA.m_value>>24)&0xFF);
return osMad;
}
Rassurez moi, y a t il l'équivalent de la fonction C fwrite qui permettrait
de sauvegarder mes données au format binaires ?
Merci
oMadStream& operator<<(oMadStream& osMad, const A& rcA)
{
osMad << "mad";
osMad << static_cast<char> ((rcA.m_value )&0xFF);
osMad << static_cast<char> ((rcA.m_value>> 8)&0xFF);
osMad << static_cast<char> ((rcA.m_value>>16)&0xFF);
osMad << static_cast<char> ((rcA.m_value>>24)&0xFF);
return osMad;
}
Rassurez moi, y a t il l'équivalent de la fonction C fwrite qui permettrait
de sauvegarder mes données au format binaires ?
Merci
Dans mon projet, je souhaite sauvegarder mes données sous plusieurs
formats. Pour cela, j'ai décider de dériver plusieurs classes de
ofstream (autant que de format), et de surcharger l'operator<< pour
chacune.
Pour les format de type texte, il n'y a pas de problemes, mais pour
les formats binaires, la seul solution que j'ai trouvé me semble
<tres> lourde, voyez plutot :
#include <iostream>
#include <fstream>
using namespace std;
class A
{
public:
A():m_value(77) {}
virtual ~A() {}
public:
int m_value;
};
class oMadStream : public ofstream
{
public:
oMadStream(const char* sTitre)
{
open(sTitre, ios_base::out|ios_base::trunc|ios_base::binary);
}
};
oMadStream& operator<<(oMadStream& osMad, const A& rcA)
{
osMad << "mad";
osMad << static_cast<char> ((rcA.m_value )&0xFF);
osMad << static_cast<char> ((rcA.m_value>> 8)&0xFF);
osMad << static_cast<char> ((rcA.m_value>>16)&0xFF);
osMad << static_cast<char> ((rcA.m_value>>24)&0xFF);
return osMad;
}
ostream& operator<<(ostream& os, const A& rcA)
{
os << "m_value=" << rcA.m_value << endl;
return os;
}
int main(void)
{
A a;
cout << a;
oMadStream mad("test.mad");
if (mad.is_open())
{
mad << a;
mad.close();
}
return 0;
}
Rassurez moi, y a t il l'équivalent de la fonction C fwrite qui
permettrait de sauvegarder mes données au format binaires ?
Dans mon projet, je souhaite sauvegarder mes données sous plusieurs
formats. Pour cela, j'ai décider de dériver plusieurs classes de
ofstream (autant que de format), et de surcharger l'operator<< pour
chacune.
Pour les format de type texte, il n'y a pas de problemes, mais pour
les formats binaires, la seul solution que j'ai trouvé me semble
<tres> lourde, voyez plutot :
#include <iostream>
#include <fstream>
using namespace std;
class A
{
public:
A():m_value(77) {}
virtual ~A() {}
public:
int m_value;
};
class oMadStream : public ofstream
{
public:
oMadStream(const char* sTitre)
{
open(sTitre, ios_base::out|ios_base::trunc|ios_base::binary);
}
};
oMadStream& operator<<(oMadStream& osMad, const A& rcA)
{
osMad << "mad";
osMad << static_cast<char> ((rcA.m_value )&0xFF);
osMad << static_cast<char> ((rcA.m_value>> 8)&0xFF);
osMad << static_cast<char> ((rcA.m_value>>16)&0xFF);
osMad << static_cast<char> ((rcA.m_value>>24)&0xFF);
return osMad;
}
ostream& operator<<(ostream& os, const A& rcA)
{
os << "m_value=" << rcA.m_value << endl;
return os;
}
int main(void)
{
A a;
cout << a;
oMadStream mad("test.mad");
if (mad.is_open())
{
mad << a;
mad.close();
}
return 0;
}
Rassurez moi, y a t il l'équivalent de la fonction C fwrite qui
permettrait de sauvegarder mes données au format binaires ?
Dans mon projet, je souhaite sauvegarder mes données sous plusieurs
formats. Pour cela, j'ai décider de dériver plusieurs classes de
ofstream (autant que de format), et de surcharger l'operator<< pour
chacune.
Pour les format de type texte, il n'y a pas de problemes, mais pour
les formats binaires, la seul solution que j'ai trouvé me semble
<tres> lourde, voyez plutot :
#include <iostream>
#include <fstream>
using namespace std;
class A
{
public:
A():m_value(77) {}
virtual ~A() {}
public:
int m_value;
};
class oMadStream : public ofstream
{
public:
oMadStream(const char* sTitre)
{
open(sTitre, ios_base::out|ios_base::trunc|ios_base::binary);
}
};
oMadStream& operator<<(oMadStream& osMad, const A& rcA)
{
osMad << "mad";
osMad << static_cast<char> ((rcA.m_value )&0xFF);
osMad << static_cast<char> ((rcA.m_value>> 8)&0xFF);
osMad << static_cast<char> ((rcA.m_value>>16)&0xFF);
osMad << static_cast<char> ((rcA.m_value>>24)&0xFF);
return osMad;
}
ostream& operator<<(ostream& os, const A& rcA)
{
os << "m_value=" << rcA.m_value << endl;
return os;
}
int main(void)
{
A a;
cout << a;
oMadStream mad("test.mad");
if (mad.is_open())
{
mad << a;
mad.close();
}
return 0;
}
Rassurez moi, y a t il l'équivalent de la fonction C fwrite qui
permettrait de sauvegarder mes données au format binaires ?
"Jeremie Fouche" writes:
Pour faire les choses vraiment bien, il ne faudrait pas derive de
std::ofstream mais de std::basic_ios (ce qui te permets d'utiliser les
streambuf et en particulier std::basic_filebuf).
"Jeremie Fouche" <jeremie.fouche.tonmasque@tiscali.fr> writes:
Pour faire les choses vraiment bien, il ne faudrait pas derive de
std::ofstream mais de std::basic_ios (ce qui te permets d'utiliser les
streambuf et en particulier std::basic_filebuf).
"Jeremie Fouche" writes:
Pour faire les choses vraiment bien, il ne faudrait pas derive de
std::ofstream mais de std::basic_ios (ce qui te permets d'utiliser les
streambuf et en particulier std::basic_filebuf).
"Jeremie Fouche" wrote in message
news:<cc13lc$mpq$...Dans mon projet, je souhaite sauvegarder mes données sous plusieurs
formats. Pour cela, j'ai décider de dériver plusieurs classes de
ofstream (autant que de format), et de surcharger l'operator<< pour
chacune.
Pourquoi l'héritage de ofstream ? Les operator<< ne sont pas virtuels.
Ils ont une sémantique bien définie dans ostream, définition qui fait
partie du contrat de la classe.
oMadStream& operator<<(oMadStream& osMad, const A& rcA)
{
osMad << "mad";
osMad << static_cast<char> ((rcA.m_value )&0xFF);
osMad << static_cast<char> ((rcA.m_value>> 8)&0xFF);
osMad << static_cast<char> ((rcA.m_value>>16)&0xFF);
osMad << static_cast<char> ((rcA.m_value>>24)&0xFF);
return osMad;
}
En général, on aurait plutôt écrit un oMadStream& operartor<<(
oMadStream&, int ) d'abord. Mais sinon, c'est la technique consacrée
pour sortir un int en binaire. (À la rigueur, on préfère l'affecter
d'abord à un unsigned, puis faire les manips sur l'unsigned. Mais la
différence n'est detectable que si la machine n'est pas à complément à
deux.)
En général, aussi, il n'y a pas besoin d'hériter de ofstream pour ça.
C'est même contre-indiqué -- si tu en hérites, et tu écris :
osMad << premierElem << deuxiemeElem ;
et quelqu'un a oublié de fournir un operator<<( oMadStream& ) pour le
type du premier élément, tu n'aurais pas d'erreur de compilation, mais
plutôt des sorties textuelles.
"Jeremie Fouche" <jeremie.fouche.tonmasque@tiscali.fr> wrote in message
news:<cc13lc$mpq$1@news.tiscali.fr>...
Dans mon projet, je souhaite sauvegarder mes données sous plusieurs
formats. Pour cela, j'ai décider de dériver plusieurs classes de
ofstream (autant que de format), et de surcharger l'operator<< pour
chacune.
Pourquoi l'héritage de ofstream ? Les operator<< ne sont pas virtuels.
Ils ont une sémantique bien définie dans ostream, définition qui fait
partie du contrat de la classe.
oMadStream& operator<<(oMadStream& osMad, const A& rcA)
{
osMad << "mad";
osMad << static_cast<char> ((rcA.m_value )&0xFF);
osMad << static_cast<char> ((rcA.m_value>> 8)&0xFF);
osMad << static_cast<char> ((rcA.m_value>>16)&0xFF);
osMad << static_cast<char> ((rcA.m_value>>24)&0xFF);
return osMad;
}
En général, on aurait plutôt écrit un oMadStream& operartor<<(
oMadStream&, int ) d'abord. Mais sinon, c'est la technique consacrée
pour sortir un int en binaire. (À la rigueur, on préfère l'affecter
d'abord à un unsigned, puis faire les manips sur l'unsigned. Mais la
différence n'est detectable que si la machine n'est pas à complément à
deux.)
En général, aussi, il n'y a pas besoin d'hériter de ofstream pour ça.
C'est même contre-indiqué -- si tu en hérites, et tu écris :
osMad << premierElem << deuxiemeElem ;
et quelqu'un a oublié de fournir un operator<<( oMadStream& ) pour le
type du premier élément, tu n'aurais pas d'erreur de compilation, mais
plutôt des sorties textuelles.
"Jeremie Fouche" wrote in message
news:<cc13lc$mpq$...Dans mon projet, je souhaite sauvegarder mes données sous plusieurs
formats. Pour cela, j'ai décider de dériver plusieurs classes de
ofstream (autant que de format), et de surcharger l'operator<< pour
chacune.
Pourquoi l'héritage de ofstream ? Les operator<< ne sont pas virtuels.
Ils ont une sémantique bien définie dans ostream, définition qui fait
partie du contrat de la classe.
oMadStream& operator<<(oMadStream& osMad, const A& rcA)
{
osMad << "mad";
osMad << static_cast<char> ((rcA.m_value )&0xFF);
osMad << static_cast<char> ((rcA.m_value>> 8)&0xFF);
osMad << static_cast<char> ((rcA.m_value>>16)&0xFF);
osMad << static_cast<char> ((rcA.m_value>>24)&0xFF);
return osMad;
}
En général, on aurait plutôt écrit un oMadStream& operartor<<(
oMadStream&, int ) d'abord. Mais sinon, c'est la technique consacrée
pour sortir un int en binaire. (À la rigueur, on préfère l'affecter
d'abord à un unsigned, puis faire les manips sur l'unsigned. Mais la
différence n'est detectable que si la machine n'est pas à complément à
deux.)
En général, aussi, il n'y a pas besoin d'hériter de ofstream pour ça.
C'est même contre-indiqué -- si tu en hérites, et tu écris :
osMad << premierElem << deuxiemeElem ;
et quelqu'un a oublié de fournir un operator<<( oMadStream& ) pour le
type du premier élément, tu n'aurais pas d'erreur de compilation, mais
plutôt des sorties textuelles.
Jean-Marc Bourguet a écrit dans le message :"Jeremie Fouche" writes:
[...]Pour faire les choses vraiment bien, il ne faudrait pas derive de
std::ofstream mais de std::basic_ios (ce qui te permets d'utiliser les
streambuf et en particulier std::basic_filebuf).
ok, merci.
J'ai bien lu aussi la réponse de James Kanze.
J'ai donc essayé ca, est ce plus propre ?
Jean-Marc Bourguet <jm@bourguet.org> a écrit dans le message :
pxb8ye3ss5h.fsf@news.bourguet.org...
"Jeremie Fouche" <jeremie.fouche.tonmasque@tiscali.fr> writes:
[...]
Pour faire les choses vraiment bien, il ne faudrait pas derive de
std::ofstream mais de std::basic_ios (ce qui te permets d'utiliser les
streambuf et en particulier std::basic_filebuf).
ok, merci.
J'ai bien lu aussi la réponse de James Kanze.
J'ai donc essayé ca, est ce plus propre ?
Jean-Marc Bourguet a écrit dans le message :"Jeremie Fouche" writes:
[...]Pour faire les choses vraiment bien, il ne faudrait pas derive de
std::ofstream mais de std::basic_ios (ce qui te permets d'utiliser les
streambuf et en particulier std::basic_filebuf).
ok, merci.
J'ai bien lu aussi la réponse de James Kanze.
J'ai donc essayé ca, est ce plus propre ?
"Jeremie Fouche" writes:
|> Jean-Marc Bourguet a écrit dans le message :
|>
|> > "Jeremie Fouche" writes:
|> [...]
|> > Pour faire les choses vraiment bien, il ne faudrait pas derive de
|> > std::ofstream mais de std::basic_ios (ce qui te permets d'utiliser
|> > les streambuf et en particulier std::basic_filebuf).
|> ok, merci.
|> J'ai bien lu aussi la réponse de James Kanze. J'ai donc essayé ca,
|> est ce plus propre ?
Nettement.
|> #include <iostream>
|> #include <fstream>
|> using namespace std;
|> class CMad
|> {
|> public:
|> CMad():m_value(15) {}
|> virtual ~CMad() {}
|> public:
|> int m_value;
|> };
|> class madStream : public ios
|> {
|> public:
|> explicit madStream(filebuf *flux)
^^^^^^^
Ici, j'utiliserais streambuf.
|> {
|> init(flux);
|> }
|> };
|> madStream& operator<<(madStream& oms, const CMad& rcMad)
|> {
|> oms.rdbuf()->sputc( (char) rcMad.m_value );
La conversion explicite n'est pas nécessaire, mais... Est-ce que ça fait
réelement ce que tu veux ?
Plus généralement, les operator<< de base doivent probablement se
modéler sur les ostream -- jusqu'au point de définir ta propre classe de
sentinelle. En gros : si on a déjà vu une erreur quelconque, on n'essaie
plus, et si on voit une erreur, il faut en positionner le bit
correspondant dans ios. Donc, en gros, pour sortir un entier, j'écrirai
quelque chose du genre (en supposant des int de 32 bits) :
madStream&
operator<<( madStream& dest, int value )
{
madStream::sentry sentry( dest ) ;
if ( sentry ) {
streambuf* sb = dest.rdbuf() ;
unsigned tmp = value ;
int shift = 32 ;
while ( dest && shift > 0 ) {
if ( sb->sputc( (tmp >> shift) & 0xff ) == EOF ) {
dest.clear( std::ios::badbit ) ;
}
shift -= 8 ;
}
}
return dest ;
}
Ça, c'est pour écrire des int comme 4 octets, poids fort d'abord, format
complément à deux. C-à-d format Internet.
Dans un premier temps au moins, madStream::sentry serait assez simple ;
quelque chose du genre :
class madStream::sentry
{
public:
sentry( madStream& dest )
: myDest( dest )
{
}
operator bool() const
{
return ! myDest.fail() ;
}
private:
madStream& myDest ;
}
Comme dans les iostream, je définirais d'abord un istream et un
ostream ; si j'ai besoin des flux bidirectionnels, j'ajouterais un
iostream dérivé des deux (mais dans l'ensemble, je préfèrerais éviter la
bidirectionnalité). Et si on prévoit la bidirectionnalité, il faut
dériver virtuellement de std::ios.
|> {
|> rMad.m_value = ims.rdbuf()->sgetc();
|> return ims;
|> }
Ici aussi, tu ne lis qu'un seul caractère. Pire, tu ne signales aucune
erreur. Comme ci-dessus :
iMadStream&
operator>>( IMadStream& source, int& value )
{
IMadStream::sentry sentry( source ) ;
if ( sentry ) {
streambuf* sb = source.rdbuf() ;
unsigned result = 0 ;
int shift = 32 ;
int tmp = sb->sgetc() ;
while ( tmp != EOF && shift > 0 ) {
shift -= 8 ;
result = result | (tmp << shift) ;
tmp = sb->sgetc() ;
}
if ( shift != 0 ) {
if ( shift == 32 ) {
source.clear( std::ios::eofbit | std::ios::failbit ) ;
} else {
source.clear( std::ios::eofbit | std::ios::badbit ) ;
}
} else {
value = tmp ;
}
}
return source ;
Ici, j'avoue ne pas suivre les conventions des istream standard, mais je
ne sais pas comment faire autrement pour permettre à l'utilisateur de
distinguer entre une vraie fin de fichier, et une erreur de formattage.
(Mais beaucoup dépend du format binaire qu'on implémente, et comment on
sait s'il y a un entier qui suit ou non.)
Aussi, l'affectation de value à la fin n'est pas garantie par la norme.
Mais ça fonctionne avec toutes les implémentations modernes, et je ne
sais pas de tête comment l'écrire d'une façon portable.
|> ostream& operator<<(ostream& os, const CMad& rcMad)
|> {
|> os << "value=" << rcMad.m_value << endl;
|> return os;
|> }
|> int main(void)
|> {
|> CMad mad;
|> filebuf fb;
|> fb.open("mad", ios::out|ios::binary|ios::trunc);
|> if ( fb.is_open() )
|> {
|> madStream oms(&fb);
|> oms << mad;
|> fb.close();
|> }
|> mad.m_value = 10;
Il faudrait tester avec d'autres valeurs. Qu'est-ce que ça donne avec
1000, par exemple ?
|> cout << mad;
|> filebuf fb2;
|> fb2.open("mad", ios::in|ios::binary);
|> if (fb2.is_open())
|> {
|> madStream ims(&fb2);
|> ims >> mad;
|> cout << mad;
|> fb2.close();
|> }
|> return 0;
|> }
|> La chose qui me gene est que j'aurai souhaité cacher le fait que le
|> filebuf doive etre ouvert en mode binaire. Peut etre mettre
|> l'initialisation du filebuf dans le constructeur de madStream ie:
|> madStream(const char* sNom, madStream::openmode mode)
|> {
|> filebuf fb;
|> fb.open(mode|ios_base::mode_binary);
|> init(&fb);
Alors, ios va stocker un pointeur au fb qui va disparaître du moment
qu'on qui le constructeur. Pas une bonne idée de tout.
La solution « consacrée », encore, c'est de se modéler sur les iostream.
Tu crées une classe dérivée, fMadStream (ou plutôt ifMadStream et
ofMadStream) qui s'occupe de la gestion du filebuf. Quelque chose du
genre :
class ifMadStream : private virtual std::filebuf, public iMadStream
...
L'astuce avec l'héritage virtuel, c'est un truc que je dois à Dietmar
Kühl -- il s'assure que le filebuf est bien initialisé avant de passer
son adresse au constructeur de iMadStream. Y compris dans le cas où on
dérive un fMadStream bidirectionnel par la suite.
"Jeremie Fouche" <jeremie.fouche.tonmasque@tiscali.fr> writes:
|> Jean-Marc Bourguet <jm@bourguet.org> a écrit dans le message :
|> pxb8ye3ss5h.fsf@news.bourguet.org...
|> > "Jeremie Fouche" <jeremie.fouche.tonmasque@tiscali.fr> writes:
|> [...]
|> > Pour faire les choses vraiment bien, il ne faudrait pas derive de
|> > std::ofstream mais de std::basic_ios (ce qui te permets d'utiliser
|> > les streambuf et en particulier std::basic_filebuf).
|> ok, merci.
|> J'ai bien lu aussi la réponse de James Kanze. J'ai donc essayé ca,
|> est ce plus propre ?
Nettement.
|> #include <iostream>
|> #include <fstream>
|> using namespace std;
|> class CMad
|> {
|> public:
|> CMad():m_value(15) {}
|> virtual ~CMad() {}
|> public:
|> int m_value;
|> };
|> class madStream : public ios
|> {
|> public:
|> explicit madStream(filebuf *flux)
^^^^^^^
Ici, j'utiliserais streambuf.
|> {
|> init(flux);
|> }
|> };
|> madStream& operator<<(madStream& oms, const CMad& rcMad)
|> {
|> oms.rdbuf()->sputc( (char) rcMad.m_value );
La conversion explicite n'est pas nécessaire, mais... Est-ce que ça fait
réelement ce que tu veux ?
Plus généralement, les operator<< de base doivent probablement se
modéler sur les ostream -- jusqu'au point de définir ta propre classe de
sentinelle. En gros : si on a déjà vu une erreur quelconque, on n'essaie
plus, et si on voit une erreur, il faut en positionner le bit
correspondant dans ios. Donc, en gros, pour sortir un entier, j'écrirai
quelque chose du genre (en supposant des int de 32 bits) :
madStream&
operator<<( madStream& dest, int value )
{
madStream::sentry sentry( dest ) ;
if ( sentry ) {
streambuf* sb = dest.rdbuf() ;
unsigned tmp = value ;
int shift = 32 ;
while ( dest && shift > 0 ) {
if ( sb->sputc( (tmp >> shift) & 0xff ) == EOF ) {
dest.clear( std::ios::badbit ) ;
}
shift -= 8 ;
}
}
return dest ;
}
Ça, c'est pour écrire des int comme 4 octets, poids fort d'abord, format
complément à deux. C-à-d format Internet.
Dans un premier temps au moins, madStream::sentry serait assez simple ;
quelque chose du genre :
class madStream::sentry
{
public:
sentry( madStream& dest )
: myDest( dest )
{
}
operator bool() const
{
return ! myDest.fail() ;
}
private:
madStream& myDest ;
}
Comme dans les iostream, je définirais d'abord un istream et un
ostream ; si j'ai besoin des flux bidirectionnels, j'ajouterais un
iostream dérivé des deux (mais dans l'ensemble, je préfèrerais éviter la
bidirectionnalité). Et si on prévoit la bidirectionnalité, il faut
dériver virtuellement de std::ios.
|> {
|> rMad.m_value = ims.rdbuf()->sgetc();
|> return ims;
|> }
Ici aussi, tu ne lis qu'un seul caractère. Pire, tu ne signales aucune
erreur. Comme ci-dessus :
iMadStream&
operator>>( IMadStream& source, int& value )
{
IMadStream::sentry sentry( source ) ;
if ( sentry ) {
streambuf* sb = source.rdbuf() ;
unsigned result = 0 ;
int shift = 32 ;
int tmp = sb->sgetc() ;
while ( tmp != EOF && shift > 0 ) {
shift -= 8 ;
result = result | (tmp << shift) ;
tmp = sb->sgetc() ;
}
if ( shift != 0 ) {
if ( shift == 32 ) {
source.clear( std::ios::eofbit | std::ios::failbit ) ;
} else {
source.clear( std::ios::eofbit | std::ios::badbit ) ;
}
} else {
value = tmp ;
}
}
return source ;
Ici, j'avoue ne pas suivre les conventions des istream standard, mais je
ne sais pas comment faire autrement pour permettre à l'utilisateur de
distinguer entre une vraie fin de fichier, et une erreur de formattage.
(Mais beaucoup dépend du format binaire qu'on implémente, et comment on
sait s'il y a un entier qui suit ou non.)
Aussi, l'affectation de value à la fin n'est pas garantie par la norme.
Mais ça fonctionne avec toutes les implémentations modernes, et je ne
sais pas de tête comment l'écrire d'une façon portable.
|> ostream& operator<<(ostream& os, const CMad& rcMad)
|> {
|> os << "value=" << rcMad.m_value << endl;
|> return os;
|> }
|> int main(void)
|> {
|> CMad mad;
|> filebuf fb;
|> fb.open("mad", ios::out|ios::binary|ios::trunc);
|> if ( fb.is_open() )
|> {
|> madStream oms(&fb);
|> oms << mad;
|> fb.close();
|> }
|> mad.m_value = 10;
Il faudrait tester avec d'autres valeurs. Qu'est-ce que ça donne avec
1000, par exemple ?
|> cout << mad;
|> filebuf fb2;
|> fb2.open("mad", ios::in|ios::binary);
|> if (fb2.is_open())
|> {
|> madStream ims(&fb2);
|> ims >> mad;
|> cout << mad;
|> fb2.close();
|> }
|> return 0;
|> }
|> La chose qui me gene est que j'aurai souhaité cacher le fait que le
|> filebuf doive etre ouvert en mode binaire. Peut etre mettre
|> l'initialisation du filebuf dans le constructeur de madStream ie:
|> madStream(const char* sNom, madStream::openmode mode)
|> {
|> filebuf fb;
|> fb.open(mode|ios_base::mode_binary);
|> init(&fb);
Alors, ios va stocker un pointeur au fb qui va disparaître du moment
qu'on qui le constructeur. Pas une bonne idée de tout.
La solution « consacrée », encore, c'est de se modéler sur les iostream.
Tu crées une classe dérivée, fMadStream (ou plutôt ifMadStream et
ofMadStream) qui s'occupe de la gestion du filebuf. Quelque chose du
genre :
class ifMadStream : private virtual std::filebuf, public iMadStream
...
L'astuce avec l'héritage virtuel, c'est un truc que je dois à Dietmar
Kühl -- il s'assure que le filebuf est bien initialisé avant de passer
son adresse au constructeur de iMadStream. Y compris dans le cas où on
dérive un fMadStream bidirectionnel par la suite.
"Jeremie Fouche" writes:
|> Jean-Marc Bourguet a écrit dans le message :
|>
|> > "Jeremie Fouche" writes:
|> [...]
|> > Pour faire les choses vraiment bien, il ne faudrait pas derive de
|> > std::ofstream mais de std::basic_ios (ce qui te permets d'utiliser
|> > les streambuf et en particulier std::basic_filebuf).
|> ok, merci.
|> J'ai bien lu aussi la réponse de James Kanze. J'ai donc essayé ca,
|> est ce plus propre ?
Nettement.
|> #include <iostream>
|> #include <fstream>
|> using namespace std;
|> class CMad
|> {
|> public:
|> CMad():m_value(15) {}
|> virtual ~CMad() {}
|> public:
|> int m_value;
|> };
|> class madStream : public ios
|> {
|> public:
|> explicit madStream(filebuf *flux)
^^^^^^^
Ici, j'utiliserais streambuf.
|> {
|> init(flux);
|> }
|> };
|> madStream& operator<<(madStream& oms, const CMad& rcMad)
|> {
|> oms.rdbuf()->sputc( (char) rcMad.m_value );
La conversion explicite n'est pas nécessaire, mais... Est-ce que ça fait
réelement ce que tu veux ?
Plus généralement, les operator<< de base doivent probablement se
modéler sur les ostream -- jusqu'au point de définir ta propre classe de
sentinelle. En gros : si on a déjà vu une erreur quelconque, on n'essaie
plus, et si on voit une erreur, il faut en positionner le bit
correspondant dans ios. Donc, en gros, pour sortir un entier, j'écrirai
quelque chose du genre (en supposant des int de 32 bits) :
madStream&
operator<<( madStream& dest, int value )
{
madStream::sentry sentry( dest ) ;
if ( sentry ) {
streambuf* sb = dest.rdbuf() ;
unsigned tmp = value ;
int shift = 32 ;
while ( dest && shift > 0 ) {
if ( sb->sputc( (tmp >> shift) & 0xff ) == EOF ) {
dest.clear( std::ios::badbit ) ;
}
shift -= 8 ;
}
}
return dest ;
}
Ça, c'est pour écrire des int comme 4 octets, poids fort d'abord, format
complément à deux. C-à-d format Internet.
Dans un premier temps au moins, madStream::sentry serait assez simple ;
quelque chose du genre :
class madStream::sentry
{
public:
sentry( madStream& dest )
: myDest( dest )
{
}
operator bool() const
{
return ! myDest.fail() ;
}
private:
madStream& myDest ;
}
Comme dans les iostream, je définirais d'abord un istream et un
ostream ; si j'ai besoin des flux bidirectionnels, j'ajouterais un
iostream dérivé des deux (mais dans l'ensemble, je préfèrerais éviter la
bidirectionnalité). Et si on prévoit la bidirectionnalité, il faut
dériver virtuellement de std::ios.
|> {
|> rMad.m_value = ims.rdbuf()->sgetc();
|> return ims;
|> }
Ici aussi, tu ne lis qu'un seul caractère. Pire, tu ne signales aucune
erreur. Comme ci-dessus :
iMadStream&
operator>>( IMadStream& source, int& value )
{
IMadStream::sentry sentry( source ) ;
if ( sentry ) {
streambuf* sb = source.rdbuf() ;
unsigned result = 0 ;
int shift = 32 ;
int tmp = sb->sgetc() ;
while ( tmp != EOF && shift > 0 ) {
shift -= 8 ;
result = result | (tmp << shift) ;
tmp = sb->sgetc() ;
}
if ( shift != 0 ) {
if ( shift == 32 ) {
source.clear( std::ios::eofbit | std::ios::failbit ) ;
} else {
source.clear( std::ios::eofbit | std::ios::badbit ) ;
}
} else {
value = tmp ;
}
}
return source ;
Ici, j'avoue ne pas suivre les conventions des istream standard, mais je
ne sais pas comment faire autrement pour permettre à l'utilisateur de
distinguer entre une vraie fin de fichier, et une erreur de formattage.
(Mais beaucoup dépend du format binaire qu'on implémente, et comment on
sait s'il y a un entier qui suit ou non.)
Aussi, l'affectation de value à la fin n'est pas garantie par la norme.
Mais ça fonctionne avec toutes les implémentations modernes, et je ne
sais pas de tête comment l'écrire d'une façon portable.
|> ostream& operator<<(ostream& os, const CMad& rcMad)
|> {
|> os << "value=" << rcMad.m_value << endl;
|> return os;
|> }
|> int main(void)
|> {
|> CMad mad;
|> filebuf fb;
|> fb.open("mad", ios::out|ios::binary|ios::trunc);
|> if ( fb.is_open() )
|> {
|> madStream oms(&fb);
|> oms << mad;
|> fb.close();
|> }
|> mad.m_value = 10;
Il faudrait tester avec d'autres valeurs. Qu'est-ce que ça donne avec
1000, par exemple ?
|> cout << mad;
|> filebuf fb2;
|> fb2.open("mad", ios::in|ios::binary);
|> if (fb2.is_open())
|> {
|> madStream ims(&fb2);
|> ims >> mad;
|> cout << mad;
|> fb2.close();
|> }
|> return 0;
|> }
|> La chose qui me gene est que j'aurai souhaité cacher le fait que le
|> filebuf doive etre ouvert en mode binaire. Peut etre mettre
|> l'initialisation du filebuf dans le constructeur de madStream ie:
|> madStream(const char* sNom, madStream::openmode mode)
|> {
|> filebuf fb;
|> fb.open(mode|ios_base::mode_binary);
|> init(&fb);
Alors, ios va stocker un pointeur au fb qui va disparaître du moment
qu'on qui le constructeur. Pas une bonne idée de tout.
La solution « consacrée », encore, c'est de se modéler sur les iostream.
Tu crées une classe dérivée, fMadStream (ou plutôt ifMadStream et
ofMadStream) qui s'occupe de la gestion du filebuf. Quelque chose du
genre :
class ifMadStream : private virtual std::filebuf, public iMadStream
...
L'astuce avec l'héritage virtuel, c'est un truc que je dois à Dietmar
Kühl -- il s'assure que le filebuf est bien initialisé avant de passer
son adresse au constructeur de iMadStream. Y compris dans le cas où on
dérive un fMadStream bidirectionnel par la suite.