どのようにのstd :: ostreamに継承するには?
-
12-09-2019 - |
質問
私の周りグーグルでてきたと私はちょうどこれに対する単純な答えを見つけることができません。そして、それは、STLは、一般的であるとして、シンプルである必要があります。
私はのstd :: ostreamにから公に継承MyOStreamを定義したいです。のは、私は毎回何かが私のストリームに書かれている)(FOOを呼び出したいとしましょう。
class MyOStream : public ostream {
public:
...
private:
void foo() { ... }
}
私はのostreamのパブリックインターフェイスは、非仮想であることを理解し、それがどのように行うことができますか? 私は、クライアントがオペレータ<<と書き込み(両方を使用できるようにしたい)とput()MyOStreamに、私のクラスの拡張機能を使用しています。
解決
これは、残念ながら、簡単な質問ではありません。あなたがから派生する必要がありますクラスは、このようなbasic_
としてbasic_ostream
クラスです。ただし、ストリームから導出はあなたが望むものではないかもしれないが、あなたの代わりに、ストリームバッファから派生して、既存のストリームクラスをインスタンス化し、このクラスを使用することもできます。
全領域が複雑ですが、それについての優れた本があります標準C ++入出力ストリームとロケール、これは私はあなたが先に進む前に、見てみましょうお勧めします。
他のヒント
私は同じことを行う方法のまわりで私の頭を回転させていたと私はそれが難しい、実際にはありませんが分かりました。 基本的にはただのostreamとストリームバッファオブジェクトのサブクラス、およびバッファとしてそれ自体とのostreamを構築します。 std :: streambufのから仮想オーバーフロー()ストリームに送信されたすべての文字のために呼び出されます。あなたの例に合わせて、私はちょうどのfoo()関数を作って、それを呼ばれます。
struct Bar : std::ostream, std::streambuf
{
Bar() : std::ostream(this) {}
int overflow(int c)
{
foo(c);
return 0;
}
void foo(char c)
{
std::cout.put(c);
}
};
void main()
{
Bar b;
b<<"Look a number: "<<std::hex<<29<<std::endl;
}
主な機能は、実際の主な機能はないという事実を無視して、ああ。これは、他の場所から呼び出された名前空間にあります; P
と同様の効果を達成するために別の作業ハックは、テンプレートと組成物を使用することである。
class LoggedStream {
public:
LoggedStream(ostream& _out):out(_out){}
template<typename T>
const LoggedStream& operator<<(const T& v) const {log();out << v;return *this;}
protected:
virtual void log() = 0;
ostream& out;
};
class Logger : LoggedStream {
void log() { std::cerr << "Printing" << std::endl;}
};
int main(int,char**) {LoggedStream(std::cout) << "log" << "Three" << "times";}
これが正解であるかどうかは知らないが、私はのstd :: ostreamにからこの方法を継承しています。これは、STDから継承されたバッファ:: basic_streambufを使用し、(フラッシュ場合以下)一度に64個の文字を取得し、データの実際の処理が行われている一般的なputChars()メソッドに送信します。また、ユーザーのデータを提供する方法を示します。
#include <streambuf>
#include <ostream>
#include <iostream>
//#define DEBUG
class MyData
{
//example data class, not used
};
class MyBuffer : public std::basic_streambuf<char, std::char_traits<char> >
{
public:
inline MyBuffer(MyData data) :
data(data)
{
setp(buf, buf + BUF_SIZE);
}
protected:
// This is called when buffer becomes full. If
// buffer is not used, then this is called every
// time when characters are put to stream.
inline virtual int overflow(int c = Traits::eof())
{
#ifdef DEBUG
std::cout << "(over)";
#endif
// Handle output
putChars(pbase(), pptr());
if (c != Traits::eof()) {
char c2 = c;
// Handle the one character that didn't fit to buffer
putChars(&c2, &c2 + 1);
}
// This tells that buffer is empty again
setp(buf, buf + BUF_SIZE);
return c;
}
// This function is called when stream is flushed,
// for example when std::endl is put to stream.
inline virtual int sync(void)
{
// Handle output
putChars(pbase(), pptr());
// This tells that buffer is empty again
setp(buf, buf + BUF_SIZE);
return 0;
}
private:
// For EOF detection
typedef std::char_traits<char> Traits;
// Work in buffer mode. It is also possible to work without buffer.
static const size_t BUF_SIZE = 64;
char buf[BUF_SIZE];
// This is the example userdata
MyData data;
// In this function, the characters are parsed.
inline void putChars(const char* begin, const char* end){
#ifdef DEBUG
std::cout << "(putChars(" << static_cast<const void*>(begin) <<
"," << static_cast<const void*>(end) << "))";
#endif
//just print to stdout for now
for (const char* c = begin; c < end; c++){
std::cout << *c;
}
}
};
class MyOStream : public std::basic_ostream< char, std::char_traits< char > >
{
public:
inline MyOStream(MyData data) :
std::basic_ostream< char, std::char_traits< char > >(&buf),
buf(data)
{
}
private:
MyBuffer buf;
};
int main(void)
{
MyData data;
MyOStream o(data);
for (int i = 0; i < 8; i++)
o << "hello world! ";
o << std::endl;
return 0;
}
作曲ではなく、継承。あなたのクラスは、(FOO()を呼び出した後)、それまでのostream&、と前方に "ラップ" 含まれています。