1

C++ でレポート/ロガー クラスを作成しようとしています。

Report というオブジェクトをメインに持ち、このクラスに演算子 << を適用して、ofstream と同じように複数の文字列をファイルに書き込みたいと考えています。

したがって、次のコードを使用する代わりに:

  ofstream myfile ("d://example.txt");
  if (myfile.is_open())
  {
    myfile << "This is a line.\n" << "Heya!!!" << endl;
    myfile.close();
  }

次のようなものが欲しいです:

  Report rLogger ("d://example.txt"); // Report C'tor (const string& s)
  logger << "This is a line.\n" << "Heya!!!" << endl;
// the destructor of rLogger will close the file when it dies...

演算子 << をメンバー関数として記述する方法が見つかりません。これはまさにここで必要なものと思われます。演算子 << を使用できる唯一の方法は、この場合は役に立たない友人としてです。誰かが上記のように実装する方法を教えてもらえますか?

前もってありがとう、ガイ

4

5 に答える 5

4

次のことを試してください。

class Report {
    public:
        Report() {}

        Report(std::string _str) : stream(_str) {}

        Report& operator <<(std::string str) {
            if (stream.is_open())
                stream << str;

            return *this;
        }

        ~Report() { stream.close(); }

        std::ofstream stream;
};

上記の場合、<string>ヘッダーも含める必要があります。

于 2013-01-26T18:14:11.840 に答える
4

ストリームのようなタイプを作成したいようです。出力演算子をオーバーロードしてストリームのような型を作成しないでください<<。新しいストリームのような型を作成する方法は、ストリーム バッファ (つまり、 から派生した型) を作成し、これを使用してオブジェクトstd::streambufを初期化することです。std::ostreamstd::ostream

オーバーロードの他のアプローチは、次のoperator<<()ようなマニピュレーターには機能しませんstd::endl。マニピュレーターstd::endlは関数テンプレートであり、使用時にテンプレート引数を推定するには、正しい型を推定するために使用できるオーバーロードが必要です。std::ostreamクラスは、適切な特別なオーバーロードを提供することでこれを行います。

これは、メンバーとしてオーバーロードする方法についてのあなたの質問に答えていないことを認識していますoperator<<()が、それは間違ったアプローチであり、問​​題への対処方法を変更することでおそらくより良い結果が得られると思います. 対応するクラスを作成する方法について詳しく説明しますが、十分なコンテキストが提供されていません。

于 2013-01-26T18:58:25.240 に答える
2

"Heya!!!"またはなど、レポートにさまざまなタイプを挿入する必要があるために問題が発生しているようstd::endlです。

柔軟な解決策の 1 つは、テンプレートを使用してこれを行うことです。

Reportが指すメンバー関数として実装できますthis

class Report {
    public:

        template < typename T >
        Report& operator <<( const T &data ) { ... }

};

または、フレンド関数として、存在せずthisReport代わりに明示的に言及され、名前が付けられています。

class Report {
    public:

        template < typename T >
        friend Report& operator <<( Report &r, const T &data ) { ... }

};

Reportまたは、ジョブを実行するのに十分なパブリック メソッドがある場合は、スタンドアロン関数として。

template < typename T >
Report& operator <<( Report &r, const T &data ) { ... }
于 2013-01-26T18:40:22.460 に答える
1

メンバー関数として実装し、複数のストリームを連結できるようにするには、関数の最後でオブジェクトへの参照を返すだけです。

class Report {
public:

    // ...

    Report& operator<<(const char *text) {
        // write text to file...

        return *this;
    }

};

ファイルの代わりに標準出力に出力する非常に簡単な例を次に示します: http://codepad.org/S8QeJZ1x

于 2013-01-26T18:31:41.110 に答える
1

使用後にファイルが閉じていることを確認することだけが必要な場合は、クラスReportは不要です。 std::ofstreamのデストラクタはすでにそのファイルを閉じています。

テンプレートを定義しようとするこれまでの他の回答には問題があります。実際には関数テンプレートであり、コンパイラはどのような種類のインスタンス化を使用すべきかを判断できないため、operator<<を含む一部のマニピュレータでは機能しません。std::endl

クラスの目的がReport通過するデータに何かを追加または変更することである場合、独自の streambuf を定義することで、より簡単かつ正確に実行できます。 James Kanze によるこの記事では、その方法について説明しています。

于 2013-01-26T19:00:08.367 に答える