C++プログラムでは、stdin
,stdout
、およびstderr
の3つのストリームがあります。これらをコンソールアプリケーションでオーバーライドし、フォームを使用するアプリケーションで使用できますか?C++ストリームをオーバーライド
たとえば、ある基底クラスではcout<< "..."
がある場合、ビジュアル(Windowsフォームのような)に「リダイレクト」できますか?
C++プログラムでは、stdin
,stdout
、およびstderr
の3つのストリームがあります。これらをコンソールアプリケーションでオーバーライドし、フォームを使用するアプリケーションで使用できますか?C++ストリームをオーバーライド
たとえば、ある基底クラスではcout<< "..."
がある場合、ビジュアル(Windowsフォームのような)に「リダイレクト」できますか?
私は何をやって推薦することは、このような入出力ストリームをラップするクラスを持っている:
#include <iostream>
#define LOG Log()
class Log
{
public:
Log(){}
~Log()
{
// Add an newline.
std::cout << std::endl;
}
template<typename T>
Log &operator << (const T &t)
{
std::cout << t;
return * this;
}
};
その後、あなたはデータがどこに行く変更したい時はいつでも、あなただけのクラスの動作を変更します。ここ は、クラスを使用する方法である:
LOG << "Use this like an iostream.";
[編集]ポテトたたきが示唆したように が、私はCOUT以外の何かに例を追加します:あなたは試してみてください理由については
#include <sstream>
#define LOG Log()
// An example with a string stream.
class Log
{
private:
static std::stringstream buf;
public:
Log(){}
~Log()
{
// Add an newline.
buf << std::endl;
}
template<typename T>
Log &operator << (const T &t)
{
buf << t;
return * this;
}
};
// Define the static member, somewhere in an implementation file.
std::stringstream Log::buf;
これは主に文字列ストリームのようなものから継承するのではなく、主にLoggerが出力する場所を簡単に変更できるためです。たとえば、次の3つの異なる出力ストリームを持つことができ、実行時に間に交換するための静的メンバ変数を使用します。これは、簡単に伐採に対処する強力な方法を作成するために拡張することができ
class Log
{
private:
static int outputIndex = 0;
// Add a few static streams in here.
static std::stringstream bufOne;
static std::stringstream bufTwo;
static std::stringstream bufThree;
public:
// Constructor/ destructor goes here.
template<typename T>
Log &operator << (const T &t)
{
// Switch between different outputs.
switch (outputIndex)
{
case 1:
bufOne << t;
break;
case 2:
bufTwo << t;
case 3:
bufThree << t;
default:
std::cout << t;
break;
}
return * this;
}
static void setOutputIndex(int _outputIndex)
{
outputIndex = _outputIndex;
}
};
// In use
LOG << "Print to stream 1";
Log::setOutputIndex(2);
LOG << "Print to stream 2";
Log::setOutputIndex(3);
LOG << "Print to stream 3";
Log::setOutputIndex(0);
LOG << "Print to cout";
。あなたは、ファイルストリームを追加し、何か他のものにiostream
インタフェースを置くためにはstd :: CERRなど
私は(原則として)同意します。 –
新しいostream派生クラスを作成して使用するほうが簡単ではないでしょうか? –
これは基本的にゼロから始まります。例えば、既存のコードがフォーマットマニピュレータや 'endl'を使用する場合はどうでしょうか?また、この例では、 'cout'以外のものとのインターフェース方法については説明していません。 – Potatoswatter
通常の方法を使用し<sstream>
にstringstream
/istringstream
/ostringstream
クラスを使用することである可能性があります。
最良の方法は、タイプistream &
とostream &
のパラメータにcin
、cout
などの使用を変更することです。それが本当に不可能な場合は、cin.rdbuf()
を修正したいストリームを指すように変更できますが、それは非常にハック的で、マルチスレッドでは機能しません。
フォームからistringstream
にテキストをコピーし、既存のコードにistream &
として渡します。完了したらstringstream
の結果をostream &
と置き換えてcout
に置き換えて、フォームにコピーします。
istringstream &
またはの引数を宣言しないでください。基本クラスを使用します。
std::basic_stringbuf<char>
をサブクラス化し、sync
とunderflow
仮想関数をオーバーライドして、ストリームを直接テキストフィールドに結び付けることができます。しかしそれはかなり進歩しており、価値がない可能性が高いです。その後
struct STDOUT_BLOCK : SLIST_ENTRY
{
char sz[];
};
class capturebuf : public std::stringbuf
{
protected:
virtual int sync()
{
if (g_threadUI && g_hwndProgressDialog) {
// ensure NUL termination
overflow(0);
// allocate space
STDOUT_BLOCK* pBlock = (STDOUT_BLOCK*)_aligned_malloc(sizeof *pBlock + pptr() - pbase(), MEMORY_ALLOCATION_ALIGNMENT);
// copy buffer into string
strcpy(pBlock->sz, pbase());
// clear buffer
str(std::string());
// queue string
::InterlockedPushEntrySList(g_slistStdout, pBlock);
// kick to log window
::PostMessageA(g_hwndProgressDialog, WM_APP, 0, 0);
}
return __super::sync();
}
};
main()
内側:ここ
'cin.rdbuf()'は変更しないでください。そして、それは「ハッキリ」ではなく、標準ライブラリiostreamがどのように使用されるように設計されているかです。 –
@Ben:グローバル変数 'cin'の基になるバッファポインタをローカル変数を指すように変更して、呼び出された関数がグローバルを介してローカルにアクセスできるようにします。それは非常にハッキリです。 – Potatoswatter
この場合も、標準のiostreamは 'streambuf'オブジェクトを置き換えるように設計されており、パブリックAPIを提供しています。これが、標準ライブラリiostreamsで多態性がどのように実装されるかです。 –
は、私はWindows上のGUIにstd::cout
をリダイレクトするために使用するコードです。もちろん、
capturebuf altout;
std::cout.set_rdbuf(&altout);
、あなたは、あなたのウィンドウにWM_APP
メッセージを処理する必要がありますSListから文字列を引き出します。しかし、これはcout
リダイレクト部分を処理します。
jweyrichが正しくメモしているように、streambuf*
を元に戻してからaltout
が範囲外になる必要があります。このコードは、そうします:
struct scoped_cout_streambuf_association
{
std::streambuf* orig;
scoped_cout_streambuf_association(std::streambuf& buf)
: orig(std::cout.rdbuf())
{
std::cout.rdbuf(&buf);
}
~scoped_cout_streambuf_association()
{
std::cout.rdbuf(orig);
}
};
そしてmain
内側:
capturebuf altout;
scoped_cout_streambuf_association redirect(altout);
終了する前に元のrdbufを復元することを忘れないでください。そうしないと、クラッシュする可能性があります。 – jweyrich
'set_rdbuf'という関数はなく、' ios :: rdbuf'の2つのオーバーロードだけです。 – Potatoswatter
@Potatoswatter:Visual C++にはこのコードがありますが、このコードはWindows固有のものですが、一般的な考え方はかなり移植性がありますが詳細はありません。 –
C++は "フォーム" を持っていません。 –
いいえ、私はコンソールではなく視覚的なものを意味します – Bakudan
通常、ストリーム動作をオーバーライドすることは、std :: streambufインターフェイスを実装することによって行われることに注意してください。それはむしろ複雑な作業なので、おそらく他の回答を使用するべきです。 – Basilevs