declaring a vector to hold an abstract class

Nov 9, 2008 at 12:14am
In my program I have an abstract base class (ABC) and two classes that derive from it. However I get compile errors if the datatype of my vector is the ABC (This makes sense because I don't want to declare instances of my ABC). Instead I tried to make the vector's datatype the derived class, but I also get compile errors. This is a slimmed down version of my program:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#..necessary includes

class ABC {

protected:
 //...
pubilc:
  ABC(int a) {..assign a ;}
  virtual ~ABC() {}
  
  //...some member funcions...
  
  //..some pure virtual member functions...
  virtual void execute() = 0;
};

class FirstDerived : public ABC {

private:
//...
public:
  FirstDerived(int a);
  virtual ~FirstDerived() {}
  
  //..pure virtual function implementation
  execute() { ..do some stuff ;}

};

FirstDerived::FirstDerived(int a):ABC(a) {

..do some stuff..

}
..and the same for the second derived class...


int main() {

ABC * tempFirstDerived[100];
ABC * tempSecondDerived[100];

for(int j = 0; j < 100; j ++) {
   tempFirstDerived[j] = new FirstDerived(j);
   tempSecondDerived[j] = new SecondDerived(j);
}

//here's where I declare the two vectors
vector <FirstDerived> * vec1 = new vector<FirstDerived>;
vector <SecondDerived> * vec2 = new vector<SecondDerived>;

for(int j = 0; j < 100; j++) {
 //here it tries to push back an object of type ABC
 //and complains
 vec1->push_back(*(tempFirstDerived[j]));
 vec2->push_back(*(tempSecondDerived[j]));
}

//next call delete on the array entries for memory management  


Then I get the compiler error:

error: no matching function for call to `std::vector<FirstDerived, std::allocator<FirstDerived> >::push_back(ABC&)'
/usr/lib/gcc/i386-redhat-linux/3.4.6/../../../../include/c++/3.4.6/bits/stl_vector.h:557: note: candidates are: void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = FirstDerived, _Alloc = std::allocator<FirstDerived>]

and the same for the second vector.
This error makes sense to me too, but I don't know what else to do.

Any solutions?

Thanks!
Last edited on Nov 9, 2008 at 1:00am
Nov 9, 2008 at 12:36am
Here you create an array of POINTERS
ABC * tempFirstDerived[100];

Here you create a (pointer to the) vector of OBJECTS
vector <FirstDerived> * vec1 = new vector<FirstDerived>;

Here you try to push a POINTER to the vector of OBJECTS
vec1->push_back(tempFirstDerived[j]);

I guess this is not the only problem, but first be determined with this.
Nov 9, 2008 at 12:59am
Sorry, that block of code should be,
1
2
3
4
5
6
for(int j = 0; j < 100; j++) {
 //here it tries to push back an object of type ABC
 //and complains
 vec1->push_back(*(tempFirstDerived[j]));
 vec2->push_back(*(tempSecondDerived[j]));
}


I'll change that in the original post. I figured that I had no good reason to have a pointer to a vector of pointers to classes.
Nov 9, 2008 at 1:09am
Use dynamic type casting to push back an object of proper type

1
2
3
4
5
for(int j = 0; j < 100; j++) 
{
	 vec1->push_back( *dynamic_cast<FirstDerived*>(tempFirstDerived[j]));
	 vec2->push_back( *dynamic_cast<SecondDerived*>(tempSecondDerived[j]));
}
Nov 9, 2008 at 1:22am
Thanks for the reply melkiy, that worked. I was afraid that the answer would be something like that - I am not very familiar with dynamic casting. I've been told that dynamic casting is bad practice, would it be better to restructure the program so as to avoid this? I'm sure there are differing opinions on this.
Nov 9, 2008 at 1:56am
mmm... there is a way to avoid dynamic_cast here. Because the code is quite simple (or not whole) i don't see a necessity of using dynamic polymorphism. So you may replace
1
2
ABC * tempFirstDerived[100];
ABC * tempSecondDerived[100];

with
1
2
FirstDerived * tempFirstDerived[100];
SecondDerived * tempSecondDerived[100];

and remove substrings like "dynamic_cast<FirstDerived*>".

But if you take advantage of this paradigm of object oriented programming, you hardly could avoid dynamic casting, though in your case you could.
The flaw of your code, i think, is that you create vectors of objects, not pointers. It works slowly and, as we see, needs explicit type casting. I suppose containing pointers might solve a number of problems and make the program more functional and strict.
Nov 9, 2008 at 4:39am
Right, The reason I wanted to do this is that I want to pass these vectors to other functions. If I do not make my classes polymorphic then I have to write a function for each of the derived classes even if I'm doing manipulations that just involve the base class functions. By using polymorphism I can write one function that takes an ABC.

The reason I wanted to create vectors of objects and not pointers is not very strong: When I am looping over a vector of objects, I get an iterator vector<ABC>::iterator itr= vec1->begin() and then to access a member function I just do itr->memberfuncion(). But if its a vector of pointers then to use the iterator I have to do (*itr)->memberfunction() which I didn't think was as nice. Maybe its worth switching to pointers in my vectors.
Nov 9, 2008 at 2:36pm
(*itr)->memberfunction() is not the ugliest construction you could see in C++ code ;). So set aside such reasoning.

You must first construct an algorithm and choose data structures you are to use to get satisfactory efficienty of the program, and only then proceed to coding. If the resulting code is not 'nice' it is not the weighty cause to change algorithm and data structures, isn't it?
Last edited on Nov 9, 2008 at 2:37pm
Nov 9, 2008 at 7:05pm
You could use boost::ptr_vector which acts identically to vector<> except that it is specialized to hold only pointers. The upshot is that iterator access does the dereference for you automatically.

Just replace vector<X> with boost::ptr_vector<X> and then replace

(*itr)->memFun();

with

itr->memFun();

Nov 9, 2008 at 8:23pm
Thanks again for all the info. I'm still deciding on the final structure of my program, but this helps alot.

Thanks!
Nov 9, 2008 at 9:57pm
I've tried using the boost library as jsmith suggested and it worked. However, in my line of work we're not avid programmers, so I might not use that to avoid confusing people who may read my code. But I will definitely keep this in mind in the future. Thanks!
Nov 9, 2008 at 10:00pm
Glad to know it helped you.

I would argue, however, that ptr_vector adds no more complexity to the code than vector, and therefore if ptr_vector is deemed to complex, then vector is also.

Nov 9, 2008 at 10:17pm
yeah, you make a good point. I would worry that someone would look at the code and say "what the heck is that?!". On the other hand it would encourage them to expand their programming knowledge. Oh by the way, melkiy had said that using a vector of objects is slower than using a vector of pointers. Is this because the vector has to handle big objects instead of pointers when resizing etc..? I find this kind of stuff interesting...does anybody know of some good documentation on programming for speed and for good memory management?
Nov 10, 2008 at 1:51pm
vector is C++'s equivalent of a C array. When the vector needs to resize itself (to make more room) the vector is reallocated and all elements are copied from the old array to the new array. This is done via copy constructor calls. This is obviously expensive for objects that are non-trivial to copy or are large. Copying pointers is easy.

You could get a copy of The Standard Template Library. It will define the complexity requirements of all the STL containers.
Topic archived. No new replies allowed.