I have a program with 3 sub-classes derived from the same class.
I need a container that will hold pointers to objects of the three sub-classes, which I can then use to call member functions in the sub-classes AND virtual member functions in the base class.
Any idea which container I should use and how I should implement it?
class Composant {};
class Button: public Composant {};
class TextBox: public Composant {};
class Menu: public Composant {};
You can just use a pointer to Composant.
1 2 3 4
Composant * objects[3];
objects[0] = new Button();
objects[1] = new TextBox();
objects[2] = new Menu();
This sould be good for virtual functions from the base class, even if the are overloaded in the sub-classes.
To access members specific to your sub classes you must cast them to that type.
Personally I'd use one of the containers in the boost::ptr_container library, but that might not be considered "STL".
Polymorphism should not affect the decision of which STL container to use; they are all the same from that perspective.
The real question is what do you want to do with the container? Will you be inserting and removing frequently? Will inserts always be at the back or can they be in the middle? Will deletes always be from the front or back or can they be in the middle? Etc.
vector is an array. Inserting anywhere into a vector other than at the end requires AT LEAST all elements beyond the insert point to be copied. Deleting from anywhere other than at the end requires all elements beyond the delete point to be copied back one location to "close the gap". Further, vector allocates enough memory for some number of elements N. As soon as you insert element N+1, vector reallocates a new array and COPIES the ENTIRE contents of your vector to the new location. For very large vectors, this is expensive, unless you know ahead of time a reasonable size and reserve the right amount of memory. Lookups in an unsorted vector are linear; in a sorted vector then can be logN, although at that point you'll need a sorted insert method which will cause your insert to be logN as well, as opposed to amortized constant time vector otherwise advertises.
list is a linked list. Inserts and deletes run in constant time with respect to list size, but at the cost of requiring a new node to be allocated for each element (ie, one call to new for every insert). Thus list will also consume a bit more memory than vector for the same size data structure. Lookups in a list, whether or not they are sorted, are essentially linear because list does not provide random access iterators.
deque is a linked list of vectors, essentially. When vector runs out of space and needs to reallocate, deque instead creates a new node, where the node is essentially another vector. Thus inserts at the front or back and deletes at the front or back run in constant time, but anywhere in the middle takes longer. Some will argue that when you're deciding between vector or deque, you should choose deque unless you need to guarantee all elements are stored contiguously in memory (which is not often a requirement).
queue is not useful; it just limits you to inserting/deleting at the front/back, and doesn't even provide you with an iterator type to walk the data structure.
set uses a linked list (tree) under the hood and thus works a lot like a list, except that set will not allow duplicate elements to be inserted. Inserts are slower than list because set needs to check for duplicates.
map is similar to set, except that what you're storing is (key, value) pairs where only the keys need to be unique.
multiset and multimap I believe have similar runtime efficiency requirements to set and map, except that they allow duplicate elements to be stored.
I have set the vector type to the base class, but this means when I try to call an over-loaded member function in one of the sub-classes, it actually runs the virtual function in the base class.
The function is one that simply prints all the member elements. The over loaded function first calls the virtual printDetails() function to print the base class member elements, then prints the member elements individual to itself. (Does this make sense?!)
If when you call an overloaded function it executes the base class function, you've probably done something wrong.
1 2 3 4 5 6 7
class Composant {
virtualvoid type() = 0; //This is an abstact function and must be declared in the sub classes.
};
class Menu: public Composant {
void type() { cout << "Menu" << endl; }
}
This should work with vectors (I am currently using the same technique for my Uni project :)