2

私は OpenGL と C++ を使用して基本的なグラフィック シーン エディターをプログラミングしています。これがコンテキストです。

  • 抽象的で、純粋な仮想関数 draw() が 1 つしかない Drawable クラスがあります。このクラスを Java インターフェイスのように使用しています。

  • Drawable を継承し、draw() を再実装する多くのクラス。

  • Drawables へのポインターのリストを含む Scene クラス。

  • その異なる Drawable オブジェクトを作成し、それらをリストに追加する main.cpp。

私はこの問題を抱えています:

  • main.cpp で作成されたオブジェクトは常に範囲外になるため、それらを作成し、参照されたオブジェクトで追加関数を実行するだけでは簡単ではありません。(常に有効なポインターのないリストを保持するだけです)。

  • ほろ苦い解決策は、これらの新しいオブジェクトを new で作成し、Scene クラスが破棄されたときにリスト内のポインターを削除するか、main.cpp でそれらを何らかの形で削除することです。

私はこれがあまり好きではないので、追加機能内のオブジェクトをコピーしてリストにコピーを保存する方法があるかどうかを尋ねたいと思います。コピーされたオブジェクトはすぐに消去されるので問題ありません。その関数内では、私が参加している Drawable のサブクラスがわかりません。Drawable は抽象クラスであるため、Drawable オブジェクトを直接コピーすることはできません。同じものに対して new を使用して Drawable オブジェクトを作成することはできません。draw() を実行できるさまざまなオブジェクトのリストが必要なだけです。念のため、いくつかのコードを残します。

class Drawable {
public:
    virtual void draw() = 0;

    virtual ~Drawable() = 0 {}
};


class Figure : public Drawable {
private:
    list<Point, allocator<Point>> _points;
    int _type;

public:
    ...

    void draw() {
        ...
    }   
};


class Scene : public Drawable {
private:
    list<Drawable*, allocator<Drawable*>> _drawables;
    ...

public:
    ...

    void add(Drawable* drawable) {
        _drawables.push_back(drawable);
    }

    ~Scene() {
        for(iterDrawable it = _drawables.begin(); it != _drawables.end(); ++it)
        delete (*it);
    }

    void draw() {
        for(iterDrawable it = _drawables.begin(); it != _drawables.end(); ++it)
            (*it)->draw();
    }   
};


main.cpp
...
void display() {
    ...

    Figure* square = new Figure(GL_POLYGON);

    square->add(Point(xSquare, ySquare));
    square->add(Point(xSquare + squareWidth, ySquare));
    square->add(Point(xSquare + squareWidth, ySquare + squareHeight));
    square->add(Point(xSquare, ySquare + squareHeight));

    cScene.add(square);
    cScene.draw();

    ...
}
...

十分に説明したことを願っています。

4

2 に答える 2

3

使用したいのは、boost ptr コンテナーです。

boost::ptr_list<Drawable>   drawlables;

/// STUFF

drawlables.add(new Square);

(スマート ポインターのコンテナーに対する) ブースト ptr コンテナーの利点は、コンテナーが要素へのアクセスを (ポインターではなく) オブジェクトのように見せることです。これにより、標準アルゴリズムでそれらを使用することが簡単になります。

ptr コンテナーは、コンテナーに挿入されたすべてのポインターの所有権を取得するため、メモリ管理がカバーされます。他のすべての場所には、コンテナーからの参照を渡す必要があります。

drawlables[0].draw();

// or drawl all of them
for_each(drawlables.begin(), drawlables.end(), std::mem_fun(&drawlables::draw));
于 2012-10-15T22:20:58.710 に答える
1
  1. Drawable仮想デストラクタが必要です。
  2. 何らかのオブジェクト所有権ポリシーを設定する必要があります。言い換えれば、割り当てたすべてのオブジェクトについて、そのオブジェクトの破棄について非常に明確な考えを持っている必要があります。これが、Java とは対照的に、C++ で行われる方法です。シーンに追加するオブジェクトを割り当てると、シーン オブジェクトがコンポーネントの最終的な所有者になりますか? 存在する場合、シーンは、deleteそれ自体がなくなる前に (つまり、デストラクタで)、そのコンポーネントのリストを取得する必要があります。シーン オブジェクトが所有者ではなく、単なるユーザーである場合、所有者は誰でしょうか? 所有者がすべてのユーザーよりも長生きすることを保証できますか? そうでない場合、所有者はどのように所有権を次の所有者に渡しますか? オブジェクトをコピーする場合は、オリジナルコピーについてこの質問を決定する必要があります。
  3. shared_ptrやのような凝ったものptr_listは立派でおしゃれですが、まず基本を学ぶことをお勧めします。なぜshared_ptrptr_listが必要なのか、どの問題を解決しようとしているのか、30000 フィートからの解決策はどのようなものかを理解することが重要です。そのような理解を得る最善の方法は、これらの問題のいくつかに出くわし、解決しようとすることです。
  4. Drawable仮想デストラクタが必要です。
  5. オブジェクトをポリモーフィックにコピーする場合は、コピーを作成するポリモーフィック関数が必要です。派生クラスごとに作成するのと同じように、派生クラスごとに自分で作成する必要がありますdraw()。このような関数の一般的に受け入れられている名前は ですclone。各 classは次のようFoocloneなります:

    virtual Foo* clone() {
        return new Foo(*this);
    }

    のバージョンはcloneすべてのクラスでほぼ同じように見えますが、それぞれを手動で作成する必要があります。これはFooのコピー コンストラクターを使用していることに注意してくださいFoo。他のオブジェクトを所有している場合、または他の方法で自明ではないコピー操作がある場合は、自分で作成する必要があります。
  6. Drawable仮想デストラクタが必要だと言いましたか?
于 2012-10-15T22:53:30.910 に答える