继承std :: istream或等效 [英] Inheriting std::istream or equivalent

查看:124
本文介绍了继承std :: istream或等效的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要通过流桥接两个库。

  QDataStream是Qt的流



和一些来自其他类似库的函数

  void read_something(istream& i); 

我无法控制QDataStream的创建方式,我不允许改变界面read_somthing函数。



我可以想到的第一件事是编写一个继承istream并封装QDataStream的类。有没有人这样做?



如果我认为这不是正确的方式,我不知道什么是最好的方式来实现。

$ b $你应该做的是编写一个streambuf,它使用QDataStream readBytes和writeBytes来实现它的功能。然后使用rdbuf将streambuf注册到一个istream中(你也可以编写一个istream后代,它在初始化时执行此操作)。



Boost包含一个旨在便于编写streambuf 。使用它可能比理解streambuf接口更简单(个人我从来没有使用它,但我写了多个streambuf;我会看看,如果我有一个例子,我可以发布)。



编辑:这里是一些东西(用法语注释 - 它来自fr.comp.lang.c ++的法语常见问题),我没有时间翻译,认为最好离开它们比去除它们),它将FILE *调用包装到streambuf中。这也是一个使用私有继承的显示情况:确保什么可以是一个成员在一个基类之前初始化。在IOStream的情况下,基类可以接收一个NULL指针,然后接收用于设置streambuf的成员init()。

  #include< stdio.h> 
#include< assert.h>

#include< iostream>
#include< streambuf>

// streambuf minimum encapsulant un FILE *
// - 利用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
//信息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:

显式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); $ c $ b assert(cstream!= NULL);
}

std :: streambuf * FILEbuf :: setbuf(char_type * s,std :: streamsize n)
{
// ne fait rien,ce qui est autorise。 Une版本加完整
// 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 chosen 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()
{
//确保实现pas strictement符合a $
// norme qui guaranteei que le test est vrai。 Cette guaranteeie 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'utilization 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:
显式oFILEstream(FILE * cstream);
};

oFILEstream :: oFILEstream(FILE * cstream)
:FILEbuf(cstream),std :: ostream(this)
{
}

// istream minimal facilitant l'utilization 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 program 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 < '\\\
';
}


I need to bridge two libraries over a stream.

QDataStream which is a stream from Qt

and some function from another libraries that looks like this

void read_something(istream& i);

I have no control over how the QDataStream is created and I'm not allowed to change the interface of read_somthing function.

The first thing I can think of is write a class that inherits istream and wraps QDataStream. Have anybody done that before?

If what I thought wasn't the proper way, I wonder what is the best way to achieve that.

解决方案

What you should do is write a streambuf which uses the QDataStream readBytes and writeBytes to implement its functions. Then register the streambuf into a istream with rdbuf (you can also write an istream descendant which does this when initialized).

Boost contains a library aiming at facilitating the writing of streambuf. It could be simpler to use it than understanding the streambuf interface (personally I never have used it but I've written multiple streambuf; I'll see if I've a example that I can post).

Edit: here is something (commented in French -- it comes from the french FAQ of fr.comp.lang.c++ --, I have no time for translation and think it is better to leave them than to remove them) which wraps FILE* call into a streambuf. This also is a show case of a use of private inheritance: ensuring that what could be a member is initialized before a base class. In the case of IOStream, the base class could as well receive a NULL pointer and then the member init() used to set the 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';
}

这篇关于继承std :: istream或等效的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆