Yep, dealing with dynamic collections of objects is when polymorphism is the most useful.
In C#, you can think of everything as being a pointer, but in C++, it isn't.
Polymorphism must be triggered through a
reference or pointer to a polymorphic object.
If you have a vector<BaseClass>, and you try to copy a DerivedClass into it,
object slicing will occur, and all the subclass information will be lost.
And because you can't have vectors of references, the only option left is to have a vector of pointers.
Here is a small example. Note that I use smart pointers here because they take care of the memory management for you. You don't actually need to use dynamic storage of the objects if you allocate everything beforehand. Actually, I'll show two examples. One with smart pointers, one without.
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
|
// Example program
#include <iostream>
#include <vector>
#include <memory>
class BaseClass {
public:
virtual void printName() const=0;
virtual ~BaseClass() { }
};
class SubClassA : public BaseClass {
virtual void printName() const override
{
std::cout << "SubClassA's getName() called\n";
}
};
class SubClassB : public BaseClass {
virtual void printName() const override
{
std::cout << "SubClassB's getName() called\n";
}
};
int main()
{
using std::vector;
std::cout << "\n(1)\n";
//
// using smart pointers:
//
{
vector<std::unique_ptr<BaseClass>> vec;
vec.push_back(std::make_unique<SubClassA>());
vec.push_back(std::make_unique<SubClassB>());
vec.push_back(std::make_unique<SubClassB>());
vec.push_back(std::make_unique<SubClassA>());
for (const auto& element : vec)
{
element->printName();
}
// (clean-up happens automatically)
}
std::cout << "\n(2)\n";
//
// without using smart pointers, or dynamic allocation of individual objects:
//
{
SubClassA a_1;
SubClassB b_1;
SubClassA a_2;
SubClassB b_2;
vector<BaseClass*> vec = { &a_1, &b_1, &a_2, &b_2 };
for (const BaseClass* element : vec)
{
element->printName();
}
// (clean-up happens automtically; objects weren't dynamically allocated)
}
std::cout << "\n(3)\n";
//
// using raw new/delete (NOT RECOMMENDED):
//
{
BaseClass* a_1 = new SubClassA();
BaseClass* b_1 = new SubClassB();
BaseClass* a_2 = new SubClassA();
BaseClass* b_2 = new SubClassB();
vector<BaseClass*> vec = { a_1, b_1, a_2, b_2 };
for (const BaseClass* element : vec)
{
element->printName();
}
delete a_1;
delete b_1;
delete a_2;
delete b_2;
}
}
|
Edit: Added virtual base-class destructor.. you need those too.