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:
#..necessary includes
class ABC {
protected:
//...
pubilc:
ABC(int a) {..assign a ;}
virtual ~ABC() {}
//...some member funcions...
//..some pure virtual member functions...
virtualvoid 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.
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.
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.
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
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.
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.
(*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?
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
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!
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.
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?
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.