TL;DR version:
Use std::vector<std::unique_ptr<Student>> db
.
Explanation
Student** db = new Student*[size]
could be used to represent an array of classes derived from Student
.
eg:
Student** db = new Student*[size];
db[0] = new Grad_Student();
db[1] = new Coop_Student();
db[2] = new Elementary_Student();
If you elect the second option
Student * db = new Student[size];
db[0] = Grad_Student();
db[1] = Coop_Student();
db[2] = Elementary_Student();
you save a lot of pesky manual memory management by directly holding Students
rather than pointers to Student
s, but Object Slicing will turn the derived Student
s into plain old Student
s. A box sized and shaped to fit a Student
can only store a Student
, so all of the additional features of, for example, the Grad_Student
assigned to db[0]
will be lost. Only by storing a reference to the Grad_Student
can the Grad_Student
's extensions be preserved. You just have to remember that the Grad_Student
is actually stored somewhere else.
Sounds good right? It is until you look at all of the dynamic allocations you have to make sure are cleaned up. Memory management is one of the hardest things to get right in C++, and one of the best ways to manage memory management is through Resource Allocation Is Initialization or RAII. std::vector
and std::unique_ptr
are fabulous examples of RAII in action.
vector
is a dynamic array all nicely wrapped up inside a class that handles virtually every aspect of list management right down to adding, removing, resizing, and making sure everything gets cleaned up. unique_ptr
is a Smart Pointer that ensures exactly one owner of a resource, and this owner will clean up the resource when it is destroyed. The result, std::vector<std::unique_ptr<Student>>
will allow you to add, remove, access, and move any Student
s without any direct intervention. This allows you to write simpler code. Simpler code is less likely to have bugs. Fewer bugs means more leisure time and happier clients. Everybody wins.