我正在尝试通过使用看起来像组合模式的东西来构建一个进度条类,该类可以具有任意数量的子进度条。
假设我有这个类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
函数,该函数会更改subbars
中pbars
的所有宽度以匹配调用它的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
我已经确认了,但似乎没有效果(。
我的代码有什么问题?它不是使用 c++0x
类型的 for 循环,因为我尝试过使用较旧的迭代器循环。我找不到我犯的错误。我认为这与我在sync
中使用setwidth
时更改了错误的pbar
有关。
免责声明:这实际上是一个更大项目的一部分,该类比此处显示的要复杂得多,但是我已经设法使用上面的代码重现了不需要的行为(顺便说一下,它不是复制粘贴的,可能包含拼写错误(
您遇到的问题是您在 sync(( 方法的循环中使用了局部变量"bar"。那就是制作每个子柱的副本,并操作副本而不是原始版本(保留在矢量中(。这就是为什么当你以后调用 show(( 方法时,你没有看到更改"坚持"的原因。
您可以通过使用引用而不是常规变量来解决此问题。尝试:
for ( pbar &bar : subbars )
{
...
}
您可能希望在 addSubBar(( 方法中进行类似的更改,因为您还要复制在向量中保存另一个副本之前传入的值。您可以通过将一个副本的参数设置为引用来跳过该副本。避免第二个副本需要更多小心来处理内存(我将留给另一个问题(。
你应该存储指向子pbars
的指针。在当前情况下,您只是存储子pbars
的副本。因此,尽管它们(内部副本(发生了变化,但外部对象并未被修改。
它不是使用 c++0x 类型的循环
实际上,根据您真正想要做的事情,它可能只是您正在使用的基于范围的for
循环。
如问题中所述,subbars
向量存储添加到其中的对象的副本 - 这可能是您想要的,也可能不是您想要的。 让我们假设它是你想要的。 您现在在pbar::sync()
中拥有的基于范围的 for 循环:
for ( pbar bar : subbars )
{
// ...
}
迭代subbars
向量,但在本例中,bar
变量本身是该subbars
向量中每个元素的副本。 因此,您对该变量所做的任何更改在每次迭代for
循环后都会丢失。
但是,如果像这样更改基于范围的for
循环:
for ( pbar& bar : subbars ) // note the `&`
{
// ...
}
现在,bar
是对subbars
向量中对象的引用,对其所做的更改将"坚持"。
但请记住,由于subbars
包含添加到其中的对象的副本,因此这些更改不会传播到添加的原始对象。 这是否是你想要的取决于你想要什么。 如果您希望更改一直传播到原始文件,则需要存储指向原始文件的指针(或智能指针(而不是副本,如 visier 的答案中所述。
您应该存储pbars
的引用而不是实例副本。