I’m trying to build a progressbar class that can have an arbitrary number of subprogressbars by using something that looks like the composition pattern.
let’s say I have this class 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
};
As you can see the pbar has two members: the width and the subprogressbars (which are themselves pbars). I’ve been trying to implememt a sync function wich changes all the widths of the pbars in subbars to match that of the pbar it was called from:
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
}
}
but this does not seem to work. I’ve tried using this test program:
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();
}
with the show function defined as:
void pbar::show() const
{
std::cout << w << std::endl;
for ( pbar bar : subbars )
{
bar.show();
}
}
The expected output would be:
1
1
1
1
yet it is:
1
2
3
4
The strange this is that the show() function does properly iterate down to all the subbars, but it looks like the sync() doesn’t (in fact, using cout I’ve affirmed that in actually does, but it seems to have no effect).
What is wrong with my code? It is not the use of the c++0x type for loop, because I’ve tried using older iterator loops. I cannot find the mistake I made. I think it has something to do with the fact that I’m changing the wrong pbars when using setwidth in sync.
disclaimer: this is actually part of a larger project and the class is a lot more complicated than is shown here, but I’ve managed to reproduce the unwanted behaviour using the above code (which by the way is not copy-pasted and might contain typo’s)
Actually, depending on what you really want to do, it might just be the range-based
forloop you’re using.As posted in the question, the
subbarsvector stores copies of the objects added to it – that may or may not be what you want. Lets assume that it is what you want. The range-based for loop that you have right now inpbar::sync():iterates over the
subbarsvector, but thebarvariable in this case is itself a copy of each element in thatsubbarsvector. So any changes you make to that variable are simply lost after each iteration of theforloop.However, if you change the range-based
forloop like so:Now,
baris a reference to the object in thesubbarsvector and changes made to it will ‘stick’.Keep in mind, however, that since
subbarscontains copies of the object that were added to it, those changes will not propagate to the original objects added. Whether or not that’s what you want depends on what it is you want. If you want the changes to propagate all the way to the originals, then you need to store pointers (or smart pointers) to the originals instead of copies, as is mentioned in visier’s answer.