7

以下は、コードがどのように見えるかの大まかなサンプルです。問題は、DerivedOne と DerivedTwo にオーバーロードされた << 演算子を持たせながら、これらのオブジェクトを Base* のベクトルに格納するにはどうすればよいかということです。

私が達成したいことについては; オブジェクト ベクトルをループして、DerivedOne と DerivedTwo に伝えた情報を出力できるようにしたいと考えています。

vector<Base*> objects;

class Base
{
 private:
 object Data
 public:
 object getData() { return Data; }
};

class DerivedOne : public Base
{
}

class DerivedTwo : public Base
{
}

これがあることはわかっていますが、私の目的では機能しません。

friend ostream &operator<<(ostream &stream, Object object)
{
    return stream << "Test" << endl;
}
4

3 に答える 3

16

仮想メソッドをプライベートにして、オブジェクトの使用方法と、派生クラスによるオブジェクトの動作のカスタマイズ方法を分離します。

これは他の回答ソリューションと似ていますが、仮想メソッドはプライベートです。

#include <iostream>

namespace {
  class Base {
    // private (there is no need to call it in subclasses)
    virtual std::ostream& doprint(std::ostream&) const = 0;
  public:
    friend std::ostream& operator << (std::ostream& os, const Base& b) {
      return b.doprint(os); // polymorphic print via reference
    }

    virtual ~Base() {} // allow polymorphic delete
  };


  class DerivedOne : public Base {
    std::ostream& doprint(std::ostream& os) const {
      return os << "One";
    }
  public:
    DerivedOne() { std::cerr << "hi " << *this << "\n"; } // use << inside class
    ~DerivedOne() { std::cerr << "bye " << *this << "\n"; }
  };
}

#include <memory>
#include <vector>

int main () {
  using namespace std;
  // wrap Base* with shared_ptr<> to put it in a vector
  vector<shared_ptr<Base>> v{ make_shared<DerivedOne>() };
  for (auto i: v) cout << *i << " ";
  cout << endl;
}

出力

hi One
One 
bye One
于 2012-08-10T18:37:59.803 に答える
6

あなたはこのようなことをすることができます:

struct Base {
    virtual ~Base () {}
    virtual std::ostream & output (std::ostream &) const = 0;
};

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

次に、に適用operator<<するBaseと、派生出力メソッドが呼び出されます。

于 2012-08-10T16:35:12.357 に答える
2

問題が説明されている限り、動的に割り当てられたポリモーフィック オブジェクトのコレクションがあります。

これらのオブジェクトが特定の設計規律にどのように準拠しているかによって、ソリューションが変わる可能性があります。

  1. あなたはオブジェクト「葉のみのオブジェクト」ですか?(他のオブジェクト自体を参照していません)?
  2. 単一の非循環参照がありますか (オブジェクトはサブオブジェクトのツリーのみを形成しますか)?
  3. 参照間に複数のパスがありますか (2 つ以上によって参照される同じオブジェクト)
  4. 循環参照はありますか?
  5. 他のオブジェクトメンバーへの参照はありますか?

状況によっては、同じオブジェクトの複数の出力を許容できるかどうか、および最終的なループをどのように回避できるかによって、状況は非常に複雑になる可能性があります。

最初にできないことはBase、値パラメーターとして使用することです (あなたの のように、それはコピーを作成するためです (オブジェクトがコピー可能であることを認めます: それらが他のオブジェクトを参照する場合、コピーは何をしますか? パスを乗算しますか? 参照されたオブジェクトを次のように複製します)良い?)

std::ostream&状況 (1.) にある場合は、すべてのリーフ オブジェクトでオーバーライドされる仮想関数が必要です。operator<<(std::ostream&, Base*)次に、オーバーロード forと別の forが必要です(std::ostream&, const std::vector<Base*>&)

このような:

class Base
{
    ...
public:
    virtual ~Base() {} //must be polymorphic
protected:
    virtual void out(std::ostream& s) =0;

    friend std::ostream& operator<<(std::ostream& st, Base* pb)
    { pb->out(st); return st; }
};

class Derived1: public Base
{
    ...
protected:
    virtual void out(std::ostream& s)
    {
        s << "Derived1 at " << this << " address " << std::endl;
    }
};


class Derived2: public Base
{
    ...
protected:
    virtual void out(std::ostream& s)
    {
        s << "Derived2 at " << this << " address " << std::endl;
    }
};

std::ostream& operator<<(std::ostream& s, const std::vector<Base*>& v)
{
    s << "there are " << v.size() << " objects:" << std::endl;
    for(auto& i:v)
        s << i;
    return s;
}

あなたが状況にある場合 (2.)

class Derived3: public Base
{
    ...
    Base* ptrOwnedobject;
};

Derived3::out所有されている子に頼る関数を実装するだけです。

状況 (3.) にあり、同じオブジェクトを長時間印刷することを許容できない場合は、異なる親が同じ子を共有しています。子を 2 回以上保存しないように何らかの方法でマークを付け、印刷が終了したらすべての子のマークを解除する必要があります (そのメカニズムを Base クラスに設定する可能性が高くなります)。

状況 (4.) にある場合、(3.) について述べたことは、無限再帰を避けるために必須になります。

状況 (5.) にある場合は、メンバーが属しているオブジェクトも検出する必要があります (自明ではありません)。複数の継承と仮想ベースもある場合...事態はさらに複雑になります。

于 2012-08-10T17:16:01.247 に答える