我需要通过一个流来连接两个库.
- QDataStream which is a stream from Qt
和另一个类似这样的库的一些功能
- void read_something(istream& i);
我无法控制如何创建QDataStream,并且我不允许更改read_somthing函数的接口.
我可以想到的第一件事是写一个继承istream并包装QDataStream的类.有人做过吗?
如果我认为不是正确的方法,我想知道什么是最好的方式来实现.
解决方法
你应该做的是写一个streambuf,它使用QDataStream readBytes和writeBytes来实现它的功能.然后使用rdbuf将streambuf注册到一个istream中(您也可以在初始化时编写一个istream descendant).
Boost包含一个旨在促进streambuf写作的图书馆.使用它可能比理解streambuf界面更简单(个人我从来没有使用过,但我已经写了多个streambuf;我会看看我有一个例子,我可以发布).
编辑:这里是一些(用法语评论 – 来自法国的fr.comp.lang.c的常见问题解答,我没有时间翻译,认为最好离开他们,而不是删除它们)包装文件*调用streambuf.这也是使用私有继承的示例:确保在基类之前初始化什么可以是成员.在IOStream的情况下,基类也可以接收一个NULL指针,然后使用成员init()来设置streambuf.
- #include <stdio.h>
- #include <assert.h>
- #include <iostream>
- #include <streambuf>
- // streambuf minimal encapsulant un FILE*
- // - utilise les tampons de FILE donc n'a pas de tampon interne en
- // sortie et a un tampon interne de taille 1 en entree car l'interface
- // de streambuf ne permet pas de faire moins;
- // - ne permet pas la mise en place d'un tampon
- // - une version plus complete devrait permettre d'acceder aux
- // informations d'erreur plus precises de FILE* et interfacer aussi
- // les autres possibilites de FILE* (entre autres synchroniser les
- // sungetc/sputbackc avec la possibilite correspondante de FILE*)
- class FILEbuf: public std::streambuf
- {
- public:
- explicit FILEbuf(FILE* cstream);
- // cstream doit etre non NULL.
- protected:
- std::streambuf* setbuf(char_type* s,std::streamsize n);
- int_type overflow(int_type c);
- int sync();
- int_type underflow();
- private:
- FILE* cstream_;
- char inputBuffer_[1];
- };
- FILEbuf::FILEbuf(FILE* cstream)
- : cstream_(cstream)
- {
- // le constructeur de streambuf equivaut a
- // setp(NULL,NULL);
- // setg(NULL,NULL,NULL);
- assert(cstream != NULL);
- }
- std::streambuf* FILEbuf::setbuf(char_type* s,std::streamsize n)
- {
- // ne fait rien,ce qui est autorise. Une version plus complete
- // devrait vraissemblablement utiliser setvbuf
- return NULL;
- }
- FILEbuf::int_type FILEbuf::overflow(int_type c)
- {
- if (traits_type::eq_int_type(c,traits_type::eof())) {
- // la norme ne le demande pas exactement,mais si on nous passe eof
- // la coutume est de faire la meme chose que sync()
- return (sync() == 0
- ? traits_type::not_eof(c)
- : traits_type::eof());
- } else {
- return ((fputc(c,cstream_) != EOF)
- ? traits_type::not_eof(c)
- : traits_type::eof());
- }
- }
- int FILEbuf::sync()
- {
- return (fflush(cstream_) == 0
- ? 0
- : -1);
- }
- FILEbuf::int_type FILEbuf::underflow()
- {
- // Assurance contre des implementations pas strictement conformes a la
- // norme qui guaranti que le test est vrai. Cette guarantie n'existait
- // pas dans les IOStream classiques.
- if (gptr() == NULL || gptr() >= egptr()) {
- int gotted = fgetc(cstream_);
- if (gotted == EOF) {
- return traits_type::eof();
- } else {
- *inputBuffer_ = gotted;
- setg(inputBuffer_,inputBuffer_,inputBuffer_+1);
- return traits_type::to_int_type(*inputBuffer_);
- }
- } else {
- return traits_type::to_int_type(*inputBuffer_);
- }
- }
- // ostream minimal facilitant l'utilisation d'un FILEbuf
- // herite de maniere privee de FILEbuf,ce qui permet de s'assurer
- // qu'il est bien initialise avant std::ostream
- class oFILEstream: private FILEbuf,public std::ostream
- {
- public:
- explicit oFILEstream(FILE* cstream);
- };
- oFILEstream::oFILEstream(FILE* cstream)
- : FILEbuf(cstream),std::ostream(this)
- {
- }
- // istream minimal facilitant l'utilisation d'un FILEbuf
- // herite de maniere privee de FILEbuf,ce qui permet de s'assurer
- // qu'il est bien initialise avant std::istream
- class iFILEstream: private FILEbuf,public std::istream
- {
- public:
- explicit iFILEstream(FILE* cstream);
- };
- iFILEstream::iFILEstream(FILE* cstream)
- : FILEbuf(cstream),std::istream(this)
- {
- }
- // petit programme de test
- #include <assert.h>
- int main(int argc,char* argv[])
- {
- FILE* ocstream = fopen("result","w");
- assert (ocstream != NULL);
- oFILEstream ocppstream(ocstream);
- ocppstream << "Du texte";
- fprintf(ocstream," melange");
- fclose(ocstream);
- FILE* icstream = fopen("result","r");
- assert (icstream != NULL);
- iFILEstream icppstream(icstream);
- std::string word1;
- std::string word2;
- icppstream >> word1;
- icppstream >> word2;
- char buf[1024];
- fgets(buf,1024,icstream);
- std::cout << "Got :" << word1 << ':' << word2 << ':' << buf << '\n';
- }