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有两个成员:宽度和子进度条(它们本身就是pbars)。我一直在尝试实现一个sync函数,它改变了 in 的所有宽度pbarssubbars匹配pbar它被调用的宽度:

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我已经确认 in 实际上确实这样做了,但它似乎没有效果)。

我的代码有什么问题?这不是c++0xfor 循环类型的使用,因为我尝试过使用较旧的迭代器循环。我找不到我犯的错误。我认为这与我pbar在使用setwidthin时更改了错误的 s 的事实有关sync

免责声明:这实际上是一个更大项目的一部分,并且该类比此处显示的要复杂得多,但是我已经设法使用上面的代码重现了不需要的行为(顺便说一下,它不是复制粘贴的,可能包含错字)

4

4 回答 4

5

您遇到的问题是您在 sync() 方法的循环中使用了局部变量“bar”。那就是制作每个子栏的副本,并操纵副本而不是原始版本(保留在向量中)。这就是为什么当您稍后调用 show() 方法时没有看到更改“坚持”的原因。

您可以通过使用引用而不是常规变量来解决此问题。尝试:

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

您可能希望在 addSubBar() 方法中进行类似的更改,因为在将另一个副本保存到向量中之前,您还要复制传入的值。您可以通过将其参数设为引用来跳过一个副本。避免第二个副本需要更加小心处理内存(我将留给另一个问题)。

于 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 的回答中所述

于 2012-05-19T21:02:22.203 回答
0

您应该存储引用pbars而不是实例副本。

于 2012-05-19T21:06:26.260 回答