Conainers and sub-classes

Hi, I need a bit of help,

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?

Thanks
Assuming something like :
1
2
3
4
5
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.
 
((Menu *)objects[2])->showMenu();
Last edited on
Thanks but, sadly, I have to use a container from the STL.

Any other suggestions?

Thanks
vector?
1
2
3
4
5
using std::vector;

vector<Conposant *> objects;

objects.push_back(new Menu());
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.
That does work to a certain extent.

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?!)

Any ideas why and how I can fix this?

Thanks
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 {
	virtual void 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 :)

closed account (z05DSL3A)
@ehhartley

Possibly being a bit pedantic but are really talking about overloading or are you talking about overriding?

To address your issue it would be helpfull to see some code.
OK, here's some code. I've only included the bits you need to understand the problem.

There are 2 other subclasses to be included in the vector so I can't make it Vector<class Book>.

Remember I am a NOVICE so it's probably not very pretty, also the reason why I don't know he difference between overloading and overriding!!


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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#include <iostream>
#include <string>
#include <vector>

using namespace std;

class Entry {
public:
	int id;
	int number;
	string name;
	int borrowed;
	string borrowedBy;

	Entry(int number){
		id = number;
		borrowed = 0;
		cout << endl << "Please enter the item name:" << endl;
		cin >> name;
	}

	Entry(){
		cout << "Please enter the item ID:" << endl;
		cin >> id;

		borrowed = 0;

		cout << "Please enter the item name:" << endl;
		cin >> name;
	}

	~Entry(){}

	virtual void entryBorrowed();
	void entryReturned();
	virtual void printDetails(){
		cout << endl << "ID: " << id << endl;
		cout << "Borrowed? " ;

		if (borrowed == 1) {
			cout << "Yes" << endl;
			cout << "Borrowed by: " << borrowedBy << endl;
		}

		else
			cout << "No" << endl;
	
		cout << "Name: " << name << endl;
	}
};

class Book : public Entry {
public:
	string author;
	string publisher;
	string edition;
	string year;

	Book (int number) : Entry(number){
		cout << endl << "Please enter the Author:" << endl;
		cin >> author;

		cout<< endl << "Please enter the Publisher:" << endl;
		cin >> publisher;

		cout << endl << "Please enter the Edition:" << endl;
		cin >> edition;

		cout << endl << "Please enter the Year:" << endl;
		cin >> year;
	}

	Book () : Entry(){
		cout << endl << "Please enter the Author:" << endl;
		cin >> author;

		cout<< endl << "Please enter the Publisher:" << endl;
		cin >> publisher;

		cout << endl << "Please enter the Edition:" << endl;
		cin >> edition;

		cout << endl << "Please enter the Year:" << endl;
		cin >> year;
	}

	~Book(){}

	void printDetails(){
		Entry::printDetails();
		cout << "Author: " << author << endl;
		cout << "Publisher: " << publisher << endl;
		cout << "Edition: " << edition << endl;
		cout << "Year: " << year << endl;
	}
};


void main(){

	vector <class Entry> libCatalogue;

	Book* b = new Book(1);


	libCatalogue.push_back(*b);
	libCatalogue[0].printDetails();

}


Output:

ID: 1
Borrowed? No
Name: 1

Output needs to include Book::printDetails() as well.

Thanks
closed account (z05DSL3A)
See if this works:
1
2
3
4
5
6
7
8
9
void main()
{
    vector <Entry*> libCatalogue;
    Entry* b = new Book(1);
	
    libCatalogue.push_back(b);
    libCatalogue[0]->printDetails();

}

I'm at work so can't give a lot of time to explain, maybe later.
That's sorted it, thanks very much.

If you get chance can you explain what the -> does?

Thanks
closed account (z05DSL3A)
For the -> operator look at Pointers to classes here:
http://www.cplusplus.com/doc/tutorial/classes.html
Topic archived. No new replies allowed.