4

コンポジションパターンのようなものを使用して、任意の数のサブプログレスバーを持つことができるプログレスバークラスを構築しようとしています。

私がこのクラスを持っているとしましょうpbar

class pbar
{
    public:
        pbar(const int w) { width = w; } // already sets the
        ~pbar() {}

         void setwidth(const int w) { width = w; } // set the width to w
         void show() const;
         void sync();

         void add(const pbar bar)
         {
              // add's a subbar
              subbars.pushback(bar);
         }

     private:
         std::vector<pbar> subbars; // the sub-process progressbars
         int width;                 // onscreen width of the pbar
};

ご覧のpbarとおり、には幅とサブプログレスバー(それ自体)の2つのメンバーがありますpbars。私は、 inのすべての幅を、それが呼び出されたときの幅と一致するようにsync変更する関数を実装しようとしてきました。pbarssubbarspbar

void pbar::sync()
{
    for ( pbar bar : subbars )
    {
         bar.setwidth(width);  // first set the width of the subbar
         bar.sync();           // secondly make it sync up it's subbars
    }
}

しかし、これはうまくいかないようです。私はこのテストプログラムを使ってみました:

int main()
{
    pbar a(1);
    pbar b(2);
    pbar c(3);
    pbar d(4);

    c.add(d);
    b.add(c);
    a.add(b);

    a.show();
    std::cout << "syncing" << std::endl;
    a.sync();
    a.show();
}

次のように定義されたshow関数を使用します。

void pbar::show() const
{
    std::cout << w << std::endl;
    for ( pbar bar : subbars )
    {
         bar.show();
    }
}

期待される出力は次のようになります。

1
1
1
1

それでもそれは:

1
2
3
4

奇妙なことに、このshow()関数はすべてのサブバーまで適切に反復されますが、そうでsync()はないように見えます(実際、実際に反復することcoutを確認しましたが、効果がないようです)。

私のコードの何が問題になっていますか?c++0x古いイテレータループを使用してみたので、typeforループの使用ではありません。私が犯した間違いを見つけることができません。pbarで使用setwidthするときに間違ったを変更しているという事実と関係があると思いますsync

免責事項:これは実際にはより大きなプロジェクトの一部であり、クラスはここに示されているよりもはるかに複雑ですが、上記のコードを使用して不要な動作を再現することができました(ちなみに、これはコピーペーストされておらず、含まれている可能性がありますタイプミス)

4

4 に答える 4

5

あなたが抱えている問題は、sync() メソッドのループでローカル変数 "bar" を使用していることです。つまり、各サブバーのコピーを作成し、元のバージョン (ベクトルに残る) ではなくコピーを操作します。これが、後で show() メソッドを呼び出したときに、変更が「固定」されていない理由です。

通常の変数の代わりに参照を使用することで、おそらくこれを修正できます。試す:

for ( pbar &bar : subbars )
{
    ...
}

ベクトルに別のコピーを保存する前に、渡す値もコピーしているため、 addSubBar() メソッドで同様の変更を行うことができます。そのパラメータを参照にすることで、1 つのコピーをスキップできます。2 番目のコピーを回避するには、メモリを処理するためにもう少し注意が必要です (これについては、別の質問に譲ります)。

于 2012-05-19T21:02:01.040 に答える
4

sub へのポインターを格納する必要がありますpbars。現在の状況では、 sub のコピーを保存しているだけですpbars。したがって、それら (内部コピー) は変更されますが、外側のオブジェクトは変更されません。

于 2012-05-19T20:21:48.273 に答える
3

c++0x 型 for ループの使用ではない

実際には、本当にやりたいことによっては、使用している範囲ベースのforループにすぎない場合があります。

質問に投稿されているように、subbarsベクターには追加されたオブジェクトのコピーが保存されます。これは、必要な場合とそうでない場合があります。それがあなたが望むものであると仮定しましょう。あなたが今持っている範囲ベースのforループpbar::sync()

for ( pbar bar : subbars )
{
    // ...
}

subbarsベクトルを反復処理しbarますが、この場合の変数はそれ自体がそのベクトルの各要素のコピーsubbarsです。したがって、その変数に加えた変更は、forループの各反復後に単に失われます。

ただし、次のように範囲ベースのforループを変更すると:

for ( pbar& bar : subbars ) // note the `&`
{
    // ...
}

はベクトルbar内のオブジェクトへの参照であり、それに加えられた変更は「固定」されます。subbars

ただし、subbars追加されたオブジェクトのコピーが含まれているため、これらの変更は追加された元のオブジェクトには反映されないことに注意してください。それが欲しいかどうかは、あなたが何を望んでいるかによって異なります。変更をオリジナルにまで反映させたい場合は、 visier's answer で述べられているように、コピーではなくオリジナルへのポインター (またはスマート ポインター) を保存する必要があります。

于 2012-05-19T21:02:22.203 に答える
0

pbarsインスタンスコピーではなく、の参照を保存する必要があります。

于 2012-05-19T21:06:26.260 に答える