JavaのtoStringに相当するC ++?


151

ストリームに書き込まれるもの、つまりcoutカスタムクラスのオブジェクトを制御する必要があります。C ++では可能ですか?JavaではtoString()、同様の目的でメソッドをオーバーライドできます。

回答:


176

C ++では、あなたは、オーバーロードすることができoperator<<ためostream、カスタムクラス:

class A {
public:
  int i;
};

std::ostream& operator<<(std::ostream &strm, const A &a) {
  return strm << "A(" << a.i << ")";
}

これにより、クラスのインスタンスをストリームに出力できます。

A x = ...;
std::cout << x << std::endl;

場合は、あなたのoperator<<欲求は、クラスの内部をプリントアウトするAと、本当にあなたはまた、フレンド関数として宣言でき、その秘密と保護されたメンバーにアクセスする必要があります。

class A {
private:
  friend std::ostream& operator<<(std::ostream&, const A&);
  int j;
};

std::ostream& operator<<(std::ostream &strm, const A &a) {
  return strm << "A(" << a.j << ")";
}

16
クラスのプライベートメンバーにアクセスする必要がある場合があるため、operator <<をクラスのフレンド関数として宣言することをお勧めします。
Naveen

5
よりよくfriend、それをとして宣言し、クラスの本体の内部でも-これを使用すると、using namespace演算子(およびクラス)を含む名前空間を指定する必要はありませんが、ADLは、そのクラスのオブジェクトが存在する限り、それを見つけますオペランドの1つ。
Pavel Minaev

...上記は、「それをクラスの本体内で友達として定義する」と言うことを意味していました-インラインメンバー定義のように。
Pavel Minaev

2
@fnieto:そのdumpパブリックメソッドはダーティで不要です。friendここでの使用は完全に問題ありません。この正確な目的のために導入されたとはfriendいえ、冗長な方法と侵入型のどちらを好むかは、完全に好みの問題ですfriend
Konrad Rudolph、

1
@Pavel:演算子がクラスと同じ名前空間で定義されている限り、引数に依存するルックアップはとにかくそれを見つけます。これは友達とは関係がなく、クラス内で宣言/定義する必要はありません。また、operator<<()メンバー関数を作成しても機能しません。std::ostream型の左側のオペランドを受け入れるには、メンバー関数をのメンバー関数にする必要がありますstd::ostream
STH

50

このようにして、ポリモーフィズムを許可することもできます。

class Base {
public:
   virtual std::ostream& dump(std::ostream& o) const {
      return o << "Base: " << b << "; ";
   }
private:
  int b;
};

class Derived : public Base {
public:
   virtual std::ostream& dump(std::ostream& o) const {
      return o << "Derived: " << d << "; ";
   }
private:
   int d;
}

std::ostream& operator<<(std::ostream& o, const Base& b) { return b.dump(o); }

3
仮想機能の+1。JavaのtoString動作をコピーします。
Konrad Rudolph、

クラスでoperator <<を直接指定するのではなく、なぜばかげているのですか?
僧侶

1
あなたは無限ループとクラッシュをしたくないので
fnieto-Fernando Nieto

1
おそらく、この手法は、シリアル化する対象のオプションを渡すのに速くて簡単です。それ以外の場合は、オプションとシリアル化するデータで初期化される別のクラスフレンドリングオペレーターを定義する必要があります。
Samuel Danielson

もう1つのポイントは、ダンプ機能の実装がインターフェイスによって実行される可能性があることです。これは、提案された演算子を使用しては不可能です。
jupp0r 2014

29

C ++ 11では、最終的にto_stringが標準に追加されました。

http://en.cppreference.com/w/cpp/string/basic_string/to_string


15
これはこのページへの便利な追加ですが、C ++の実装はJava / C#の実装とは大きく異なります。これらの言語でToString()は、はすべてのオブジェクトの基本クラスで定義される仮想関数であるため、任意のオブジェクトの文字列表現を表現する標準的な方法として使用されます。これらの関数はstd::string、組み込み型にのみ適用されます。C ++での慣用的な方法は<<、カスタム型の演算子をオーバーライドすることです。
Drew Noakes 2013年

9
の標準シグネチャの「醜さ」は、Javaのoperator<<単純なStringセマンティクスと比較して 、to_string()「有用な追加」であるだけでなく、C ++でそれを行うための新しい推奨される方法であることに気付かされます。OPのように、クラスのカスタム文字列表現Aが必要な場合は、string to_string(A a)以下の定義でclass A十分です。これは、Javaの場合と同様に継承で伝播し、Javaの場合と同様に(文字列の追加によって)組み合わせることができます。toString()Javaでオーバーライドされないものは、とにかく使用が制限されています。
P Marecki

10

Johnの発言の拡張として、文字列表現を抽出してそれをstd::stringdoに格納する場合は、次のようにします。

#include <sstream>    
// ...
// Suppose a class A
A a;
std::stringstream sstream;
sstream << a;
std::string s = sstream.str(); // or you could use sstream >> s but that would skip out whitespace

std::stringstream配置されている<sstream>ヘッダ。


2
これは、シリアル化文字列を取得するためのとんでもない面倒な方法です。
Gerd Wagner

9

質問に答えました。しかし、私は具体的な例を追加したかった。

class Point{

public:
      Point(int theX, int theY) :x(theX), y(theY)
      {}
      // Print the object
      friend ostream& operator <<(ostream& outputStream, const Point& p);
private:
      int x;
      int y;
};

ostream& operator <<(ostream& outputStream, const Point& p){
       int posX = p.x;
       int posY = p.y;

       outputStream << "x="<<posX<<","<<"y="<<posY;
      return outputStream;
}

この例では、オペレーターのオーバーロードを理解する必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.