2017-10-28 5 views
2

<<演算子のオーバーロードの戻り値の型がstd::stringの場合、コンパイラがエラーを起こしている理由を理解できません。私が理解するのを助けてくれますか?<< operator overload with std :: stringを返すエラー

ベローは再現可能な例であり、巨大なエラーが発生します。

class XY 
{ 
    int X__; 
    int Y__; 
public: 
    XY(int x, int y):X__(x), Y__(y){} 
    ~XY(){} 

    std::string operator<<(const XY_cartesiano& c) 
    { 
     std::stringstream ss; 
     ss << "{ " << X__ << ", " << Y__ << " }"; 
     return ss.str(); 
    } 

    int x() const{return X__;} 
    int y() const{return Y__;} 
}; 

void main() 
{ 

XY a(1,2); 
std::cout << a; 
} 
+1

、しかし、2つの連続したアンダースコア( 'X__'、' Y__')と大文字が続くアンダースコアで始まる名前を含む名前:あなたはあなたが得るストリームに直接書き込みます実装で使用するために予約されています。あなたのコードでそれらを使用しないでください。 –

答えて

3

のは、一例として、このようなものを見てみましょう:

cout << "My number is " << 137 << " and I like it a lot." << endl; 

これは特に

((((cout << "My number is ") << 137) << " and I like it a lot.") << endl); 

として解析されます、表現cout << "My number is "がいるのでとき、何かに評価する必要があることに気づきます<< 137で137を挿入してみてください。意味は「137をとり、coutに送信してください」という意味です。

cout << "My number is "stringを返すとした場合を想像してください。その場合、<< 137ビットは、<<演算子を左辺のstringと右辺のintの間で使用しようとしますが、これはC++では明確に定義されていません。

ストリーム挿入演算子operator <<は、これらの演算がうまく連鎖するように、左側のストリームが何であるかを参照するようにしています。そのようにして、<< 137の左側のものはcoutになります。したがって、上記のコードは本質的に一連の連鎖呼び出しで、coutに挿入されます。したがって、これらの関数のシグネチャは、通常次のようになります。

ostream& operator<< (ostream& out, const ObjectType& myObject) { 
    // ... do something to insert myObject into out ... // 
    return out; 
} 

すべてが正しく連鎖します。この関数はメンバ関数ではなく自由な関数であり、左辺はostreamの型で、右辺にはクラスの型があることに注意してください。 operator <<をメンバー関数としてオーバーロードしようとすると、左辺はクラスの型のオペランドになります。これは、ストリーム挿入がどのように動作するかを逆にしているためです。あなたのケースで<<演算子をオーバーロードする

class XY { 
public: 
     ... 
     friend ostream& operator<< (ostream& out, const XY& myXY); 
}; 

ostream& operator<< (ostream& out, const XY &myXY) { 
    ... 
    return out; 
} 
1

正しい方法あなたが持っている

ostream& operator<<(ostream& os, const XY& c) 
{ 
    os << c.X__ <<" "<< c.Y__ ; 
    return os; 
} 
+0

'os'がその幅修飾子セット(または他の一時的なストリーム修飾子)を持つ場合に、出力が部分的にマングルされないように、一度に出力される文字列全体を構築するには、おそらく内部の' ostringstream'を使うのが最善の方法です。 – templatetypedef

1

されています。あなたは、特にこの機能を実現する過程で、あなたのクラスのprivateフィールドにアクセスする必要がある場合は、それを友人を作りますstd::coutのようなstd::ostreamオブジェクトを持つ演算子を使用するときに従わなければならない規則と互換性のない方法でoperator<<をオーバーロードしました。

実際、あなたのoperator<<の署名はストリームとはまったく関係ありません! XYのメンバ関数で、別のXY(これは使用しません)を取り、文字列を返し、非正規の名前を持ちます。

XY a(1,2); 
XY b(1,2); 
std::string x = (a << b); 

ストリームで使用するためにoperator<<をオーバーロードする正しい方法は、オペレータ非メンバ関数を作成し、ストリームの参照パラメータを追加し、stream引数にストリームの参照を返すことです:あなたは理論的にはそれを呼び出すだろうか。ここです。また、文字列ストリームは必要ありません。これは問題ではありません

#include <iostream> 

class XY 
{ 
    int x; 
    int y; 
public: 
    XY(int x, int y) : x(x), y(y) {} 

    int X() const { return x; } 
    int Y() const { return y; } 
}; 

std::ostream& operator<<(std::ostream& os, XY const& c) 
{ 
    os << "{ " << c.X() << ", " << c.Y() << " }"; 
    return os; 
} 

int main() 
{ 
    XY a(1,2); 
    std::cout << a; 
} 
関連する問題