Traversing another class' private vector?

Started by
11 comments, last by cache_hit 14 years, 1 month ago
I've come into a bit of a problem with a private vector. I have 2 classes: A has a private vector of pointers. B needs to access each one of those pointers. I don't want to make the vector public since it probably should be private since it shouldn't be able to be cleared or have anything added to it from outside. I need B to somehow be able to traverse the vector and access the pointers or at least access them all somehow. How can I do that? I had some idea of passing in an iterator in an accessing function but since B doesn't know the size of the private vector, I quickly scrapped that. Would it be best just to pass a vector within B to a function in A and have that function copy all elements from the private vector to the temporary vector of B? [Edited by - Sean_Seanston on March 7, 2010 11:31:17 AM]
Advertisement
putting
friend class B;

anywhere in the declaration of class A will make every private/protected member accessible (only) for class B.
is that what you need?

ps: there are some things with the friend "relationship" you should know of and I can't find a good tutorial/paper anywhere so I'll try to recall them myself:
1) It's a one-way "relationship" if B is a friend of A, A isn't a friend of B.
2) classes that inherit from B are not friend with A (not 100% sure though).
3) you can also only declare functions as friend:
friend void doFoo(int);friend int B::justAFunction();
Give A a begin() and end() function that return a const_iterator into the vector
Quote:Original post by Sean_Seanston
B needs to access each one of those pointers.


Why?
struct Container {  template < class Visitor >  void visit(Visitor v) {    std::for_each(foos.begin(), foos.end(), v);  }private:  std::vector<Foo*> foos;];
Quote:Original post by Zahlman
Quote:Original post by Sean_Seanston
B needs to access each one of those pointers.


Why?


It needs to get an identifier from the objects that are pointed to, so that it can initialize some objects.

A is a Flyweight for B.
Quote:Original post by Antheus
struct Container {  template < class Visitor >  void visit(Visitor v) {    std::for_each(foos.begin(), foos.end(), v);  }private:  std::vector<Foo*> foos;];


This is still somewhat less flexible than just exposing an iterator to the container. For example:

class Foo{   typedef std::vector<int> ItemList_t;private:   ItemList_t items;public:   ItemList_t::iterator begin() { return items.begin(); }   ItemList_t::iterator end() { return items.end(); }   ItemList_t::const_iterator begin() const { return items.begin(); }   ItemList_t::const_iterator end() const { return items.end(); }};


For one thing, it's less code because unless your compiler supports C++0x lambdas (or you already have written a function whose sole purpose is to perform the operation of interest on these pointers) you're going to have to create a class to operate on them and then use it as a function object. This usually ends up being a lot of code for such simple matters, and creating thousands of little function objects for highly specialized purposes ends up not being very scalable in the long run.

Secondly, it allows you to base your logic on complicated relationships between the objects, with the simple visit approach each entry in the list is treated independently of the others. For example, suppose for whatever strange reason you wanted to do the following, assuming you've defined iter and end to refer to vec.begin() and vec.end() respectively.

while (iter != end){   iterator next = iter;   ++next;   if (next != end)      do_something_weird(*iter, *next);   iter = next;}


It's *possible* with the function object approach, but it's already kind of unintuitive and rapidly starts becoming less and less intuitive as you change things / make things more complicated.

For these and probably other reasons which aren't immediately popping into my head, I've adopted a pretty much universal approach of just always exposing the iterator type via a public typedef and then return both iterators and const_iterators from the class.
Can you have a method on A that returns the vector by const reference? More than just B would be able to see it, but you wouldn't have to write any boilerplate.
typedef std::vector<Foo*> FooVec;class A{    FooVec vec;    public:    const FooVec& GetVec() const{ //provides read-only access to the vector        return vec;    }};void UseVector(A& a){    const FooVec& vec = a.GetVec();    //The function can read the vector,    //but can't write it because it is const    //even if the A object isn't}
Hmmm... I hadn't thought of that Ocelot, that seems like it might be less fiddly than cache_hit's way for my purposes.

Well, I implemented the way cache_hit suggested and that worked fine, thanks. Maybe I'll have a look at returning a const reference too. It might be quicker than making 2 iterators wherever I need to do this. Unless someone points out a fatal flaw or something.
Keep in mind that if you expose the internal vector, either through const_iterators or a const reference to the vector, while you won't be able to alter the vector contents, you will allow external actors to call non-const member functions on those pointers.

This topic is closed to new replies.

Advertisement