8

私はこれに対する答えを見つけようとしていますが、私とまったく同じ問題を抱えている人は誰もいないようです.

私はいくつかの派生クラスを扱っています。これらのそれぞれの ostream 演算子 << は、それぞれに共通するものと、それぞれに固有のものを出力する必要があります。後で、これらの派生クラスからさらに派生させたいと思います。また、新しい派生クラスは、その上の「世代」にあるものを出力する必要があります。
例えば:

基本クラスの .h ファイル

class Base

{  



 int FirstClassNumber;

//The declaration I'm currently working with, that a friend gave me
//I'm pretty sure my problem lies here.


public:

friend ostream& operator << (ostream& os, const Base &base)
{
    base << os ;

    return os;
}

virtual void operator << (ostream& os) const = 0;

};

Base.cpp ファイルには、次の行が含まれています。

void Base::operator << (ostream& os)
{
  os << FirstClassNumber;
}

次に、次を導出します: (FirstDerived.h)

class FirstDerived : Public Base

{ 

int SecondClassNumber;

};

FirstDerived.cpp:

FirstDerived::operator << (ostream& os)
{
  os <<

  "The first Number is:

 //This is the line that isn't working - someone else gave me this syntax

  << Base::operator<< 

  << "The second number is"

  << SecondClassNumber;
}

次に、導出したい:

class SecondDerived: Public FirstDerived
{ 

int ThirdClassNumber;

};

Second.cpp:

FirstDerived::operator << (ostream& os)
{
  os <<

 FirstDerived::operator<<

 << "The third number is "

 << ThirdClassNumber;

 }

問題は、プログラムの最初の宣言か、のような行のいずれかである可能性が高いと思いますBase::operator<<

別の可能性は、継承されたすべてのクラスの .h ファイルで再宣言していないことです。そうすべきですか、そうであれば、どの構文を使用すればよいですか?

この方法を使用するように提案されましたstatic_castが、私の教授 (課題を書いた人であり、そのために私たちにあまり助けを与えない人) は、それを行うためのより良い方法があると言いました。助言がありますか?

4

6 に答える 6

16

このための簡単なテクニックは次のとおりです。

class Base
{  
    int FirstClassNumber;

    public:
        virtual void serialize(ostream& os) const
        {
             os << FirstClassNumber;
        }
};

// Implement the stream operator for the base class.
// All it does is call erialize which is a virtual method that
// will call the most derived version.
ostream& operator << (ostream& os, const Base &base)
{
    base.serialize(os);

    return os;
}

class FirstDerived:public Base
{  
    int SecondClassNumber;

    public:
        // Override serialize to make it call the base version.
        // Then output any local data.
        virtual void serialize(ostream& os) const
        {
             Base::serialize(os);
             os << SecondClassNumber;
        }
};
于 2011-05-17T07:27:55.623 に答える
6

ostreams の operator<< をクラス メンバーとして実装することはできません。これは、フリー (おそらくフレンド) 関数でなければなりません。これは、次の式にあるためです。

os << x;

<< の左側にあるものは、メンバー関数である場合に必要なクラスのインスタンスではありません。

子から親を呼び出すには、static_cast を実行します。

ostream & operator << ( ostream & os, const Child & c ) {
      os << static_cast <const Parent &>( c );
      // child stuff here
}

これが「最善の」解決策だと思います。または、ostream をパラメーターとして受け取る名前付き関数呼び出し Print() をクラスに与え、これを使用して operator<< を実装します。これにより、より明確なコードが得られます。

于 2011-05-17T07:03:38.660 に答える
3

@Neilの言うことは別として、仮想DoStreamメソッドを実装する方がおそらく良いので、アップキャストは必要ありません:

class Base{
private:
  virtual void DoStream(ostream& os){
    // general stuff
  }
public:
  friend ostream& operator<<(ostream& os, Base& b){
    b.DoStream(os);
    return os;
  }
};

class Derived : public Base{
private:
  void DoStream(ostream& os){
    Base::DoStream(os);
    // derived specific stuff
  }
};

したがって、オペレーターを実装する必要があるのは 1 回だけです。operator<<友達以外を公開することもできますがDoStream、それはおそらく個人的な好みです。

于 2011-05-17T07:20:17.110 に答える
1

FirstDerived.cpp:

FirstDerived::operator << (ostream& os)
{
     os <<    "The first Number is:"
   //This is the line that isn't working - someone else gave me this syntax
    << Base::operator<<
     << "The second number is"
    << SecondClassNumber;
}

後に括弧を付けて関数を呼び出し、必要な引数を提供する必要があります。戻り値がないため、ストリーミングされるもののセットに含まれるべきではありません。要約すると:

os << "The first number is: "; // finish streaming statement with ";"
Base::operator<<(os);   // separate statement to call this function...
os << "The second number is " << SecondClassNumber; // start streaming again
于 2011-05-17T07:34:46.220 に答える
0

基本クラスからメソッドを呼び出すには、次を使用できます。

Base::method(/*parameters*/)

しかしoperator<<、無料の機能です。私が見ることができる static_cast なしの唯一の可能性は、オペレーターをテンプレートとして定義し、次のように明示的に特殊化を呼び出すことです。

template<typename T>
void function(T const &t);

template<>
void function<Base>(Base const &t) {
    // own implementation ...
}

template<>
void function<Derived>(Derived const &t) {
    function<Base>(t);
    // own implementation ...
}

これは operator<< と同じ方法で実行できます。名前functionを変更してoperator<<必要なパラメータを追加するだけです。


もう 1 つの可能性は、仮想メンバー関数を作成することです。

class Base {
    virtual void print(ostream &os) const {
        // print self
    }
}; 

Derived クラスでは、Base 印刷関数を呼び出すことができます。

class Derived {
    virtual void print(ostream &os) const {
        Base::print(os);
        // print self
    }
};

operator<<そうすれば、クラスだけで十分で、Base適切な print メソッドを多態的に呼び出します。operator<<は無料の機能であることに注意してください。

ostream &operator<< (ostream &os, Base const &b) {
    b.print(os);
    return os;
}
于 2011-05-17T07:09:16.160 に答える
0

これは、ロキの答えを少し修正したものです。仮想シリアル化メソッドを使用する代わりに、仮想 to_string メソッドを使用します。これは、ostreamに出力するより多くのコンテキストで再利用できると思います。これは役立つかもしれません。

#include <iostream>
#include <string>

class Base
{
public:
  Base();
  virtual std::string to_string() const;

protected:
  int first_class_number;
  friend std::ostream& operator<<(std::ostream& os, const Base &base);
};

Base::Base()
  : first_class_number(1)
{
}

std::string Base::to_string() const
{
  return "Base: "+std::to_string(first_class_number);
}



class FirstDerived : public Base
{
public:
  FirstDerived();
  std::string to_string() const;

protected:
  int second_class_number;
};

FirstDerived::FirstDerived()
  : second_class_number(2)
{
}

std::string FirstDerived::to_string() const
{
  return "FirstDerived: "+std::to_string(first_class_number)+" "+ std::to_string(second_class_number);
}


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


int main(int argc, const char *argv[])
{
  std::cout << Base() << std::endl;
  std::cout << FirstDerived() << std::endl;
  return 0;
}

プロデュース

Base: 1 
FirstDerived: 1 2
于 2013-03-25T14:22:43.760 に答える