tags:

views:

121

answers:

2

Hi!

How do I call a method of an object which is stored within a vector? The following code fails...

    ClassA* class_derived_a = new ClassDerivedA;
    ClassA* class_another_a = new ClassAnotherDerivedA;



  vector<ClassA*> test_vector;

  test_vector.push_back(class_derived_a);
  test_vector.push_back(class_another_a);

 for (vector<ClassA*>::iterator it = test_vector.begin(); it != test_vector.end(); it++)
    it->printOutput();

The code retrieves the following error:

test3.cpp:47: error: request for member ‘printOutput’ in ‘* it.__gnu_cxx::__normal_iterator<_Iterator, _Container>::operator-> with _Iterator = ClassA**, _Container = std::vector >’, which is of non-class type ‘ClassA*’

The problem seems to be it->printOutput(); but at the moment I don't know how to call the method properly, does anyone know?

regards mikey

+13  A: 

The things in the vector are pointers. You need:

(*it)->printOutput();

which dereferences the iterator to get the pointer from the vector, then uses -> on the pointer to call the function. The syntax you show in your question would work if the vector contained objects rather than pointers, in which case the iterator acts like a pointer to one of those objects.

anon
Works, thank you!
Mike Dooley
A numerical for loop would have been the easier solution here. Iterators don't need to exist for actual iteration in the vast majority of cases - only for algorithms.
DeadMG
@DeadMG Interesting - how do you iterate a list or a map (for example) without using iterators?
anon
How often do you iterate through maps or lists? If you had a new BST or LL class, it would not be difficult to write a function to apply a given lambda or function object to each value, although iterating through the given std::map or std::list would be hard, since they use iterators as their provision for such functionality.Cases like the OP's shows exactly why they should remain encapsulated in a library or class - they're totally OTT for such simple uses.
DeadMG
Where's my edit button gone? :(It's worth mentioning that auto and decltype make their use substantially easier than in a C++03 compiler. However, their use should still be unnecessary for simple forwards iteration, rather than random-access or backwards iteration.
DeadMG
@DeadMG I can't believe that in one breath you are saying don't use iterators and in the next do use lambdas. If that is what you are saying, which is almost impossible to make out. But who cares - you have been added to my "ignore" list.
anon
A: 

There is a Boost.PointerContainer library which could help you tremendously here.

First: it takes care of memory management, so you won't forget the release the memory pointed to.
Second: it provides a "dereferenced" interface so that you can use the iterators without the ugly patching (*it)->.

#include <boost/ptr_container/ptr_vector.hpp>

int main(int argc, char* argv[])
{
  boost::ptr_vector<ClassA> vec;
  vec.push_back(new DerivedA());

  for (boost::ptr_vector<ClassA>::const_iterator it = vec.begin(), end = vec.end();
       it != end; ++it)
    it->printOutput();
}

From a Dependency Injection point of view, you might be willing to have printOutput takes a std::ostream& parameter so that you can direct it to whatever stream you want (it could perfectly default to std::cout)

Matthieu M.
Please, no "Dependency Injection" here - this is C++! We call that "passing a value to a function".
anon
I don't really understand your comment Neil, isn't dependency injection about passing the reference to an object instead of accessing the object statically ? I don't understand why the term could not be applied to C++... or do you loathe buzzwords ;) ?
Matthieu M.