2

ostream& operator<<これは、基本クラスのコードを複製せずに、派生クラスのをオーバーロードする唯一の方法ですか?キャストは避けるべきものではありませんか?

基本クラスのデータをstd::operator <<が(文字列のように)「食い尽くす」ことができるものとして表す、基本クラス内のある種の関数を定義することを除いて、他の方法はわかりません。派生クラスに対して同じことを行います(派生クラスstream内の基本クラスストリーム表現関数を呼び出します。もちろん、rep。関数を呼び出します)。

この問題の理想的な解決策は何ですか?

#include <iostream>

class Base
{
    private: 
        int b_;
    public: 
        Base()
            :
                b_()
        {};

        Base (int b)
            : 
                b_(b)
        {};

        friend std::ostream& operator<<(std::ostream& os, const Base& b);
};

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

class Derived
:
    public Base
{
    private: 
        int d_;
    public: 
        Derived()
            :
                d_()
        {};

        Derived (int b, int d)
            : 
                Base(b), 
                d_(d)
        {};

        friend std::ostream& operator<<(std::ostream& os, const Derived& b);
};

std::ostream& operator<< (std::ostream& os, const Derived& b)
{
    os << static_cast<const Base&>(b) << " " << b.d_; 
    return os;
}



using namespace std;


int main(int argc, const char *argv[])
{
    Base b(4);

    cout << b << endl;

    Derived d(4,5);

    cout << d << endl;

    return 0;
}
4

4 に答える 4

6

まあ...結果が正しく定義されていないコンテキストで行われる場合、キャストは避けるべきですが、ベースへのキャストは常に安全です。

派生参照がベース参照に減衰することを考慮することで、明示的なキャストを回避することができるため、次の場合のように暗黙的な変換を使用できます。

std::ostream& operator<< (std::ostream& os, const Derived& b)
{
    const Base& bs = b;
    os << bs << " " << b.d_; 
    return os;
}
于 2012-05-23T19:01:49.683 に答える
5
static_cast<const Base&>(b)

すべての派生クラス オブジェクトは Base クラス オブジェクトでもあり、1 つのように扱うことができるため、安全であり、誤りはありません。

キャストは、無謀な方法で使用された場合にのみ危険です。キャストは、必要な場所で正しい方法で使用する必要があります。これが、言語標準による規定のまさに目的です。

于 2012-05-23T18:33:18.070 に答える
1

次のように変更できます。

struct Base {
    int b_;
    void print(ostream &o) { o << b_; }
};

struct Derived : Base {
    int d_;
    void print(ostream &o) {
        Base::print(o);
        o << ' ' << d_;
   }
};

ostream &operator<<(ostream &o, Base &b) {
    b.print(o);
    return o;
}

ostream &operator<<(ostream &o, Derived &d) {
    d.print(o);
    return o;
}

に仮想関数がある場合Base(この例ではありません)、printそれらの 1 つである可能性があり、 の複数のオーバーロードを取り除くことができますoperator<<

于 2012-05-23T19:09:21.403 に答える
1

キャストが気に入らない場合はwriteTo、テンプレート メソッド パターンを使用して実装された関数をオペレーターに呼び出させることができます。

例えば

class Base {
   public:
       std::ostream& writeTo(std::ostream& ostr) const { os << b_; return this->doWriteTo(os); }
   private:
       int b_;

       virtual std::ostream& doWriteTo(std::ostream& ostr) const = 0; // pure virtual
};


class Derived {
    private:
        int d_;
        virtual std::ostream& doWriteTo(std::ostream& ostr) const {return ostr << d_;}
};

std::ostream& operator<<(std::ostream& ostr, const Derived& d) {
  return d.writeTo(ostr);

}

operator<<実際、このパターンを使用すると、次のように一度だけ書くことができますBase

std::ostream& operator<<(std::ostream& ostr, const Base& b) {
  return b.writeTo(ostr);

}

このパターンはまたoperator<<friend.

于 2012-05-23T19:14:06.687 に答える