In Why is there no base class in C++?, I quoted Stroustrup on why a common Object class for all classes is problematic in c++. In that quote there is the statement:
Using a universal base class implies cost: Objects must be heap-allocated to be polymorphic;
I really didn't look twice at it, and since its on Bjarnes home page I would suppose a lot of eyes have scanned that sentence and reported any misstatements.
A commenter however pointed out that this is probably not the case, and in retrospect I can't find any good reason why this should be true. A short test case yields the expected result of VDerived::f().
struct VBase {
virtual void f() { std::cout <<"VBase::f()\n"; }
};
struct VDerived: VBase {
void f() { std::cout << "VDerived::f()\n"; }
};
void test(VBase& obj) {
obj.f();
}
int main() {
VDerived obj;
test(obj);
}
Of course if the formal argument to test was test(VBase obj) the case would be totally different, but that would not be a stack vs. heap argument but rather copy semantics.
Is Bjarne flat out wrong or am I missing something here?
Addendum:
I should point out that Bjarne has added to the original FAQ that
Yes. I have simplified the arguments; this is an FAQ, not an academic paper.
I understand and sympathize with Bjarnes point. Also I suppose my eyes was one of the pairs scanning that sentence.
Looks like polymorphism to me.
Polymorphism in C++ works when you have indirection; that is, either a pointer-to-T or a reference-to-T. Where T is stored is completely irrelevant.
Bjarne also makes the mistake of saying "heap-allocated" which is technically inaccurate.
(Note: this doesn't mean that a universal base class is "good"!)
I think Bjarne means that obj, or more precisely the object it points to, can't easily be stack-based in this code:
int f(int arg)
{
std::unique_ptr<Base> obj;
switch (arg)
{
case 1: obj = std::make_unique<Derived1 >(); break;
case 2: obj = std::make_unique<Derived2 >(); break;
default: obj = std::make_unique<DerivedDefault>(); break;
}
return obj->GetValue();
}
You can't have an object on the stack which changes its class, or is initially unsure what exact class it belongs to.
(Of course, to be really pedantic, one could allocate the object on the stack by using placement-new on an alloca-allocated space. The fact that there are complicated workarounds is beside the point here, though.)
The following code also doesn't work as might be expected:
int f(int arg)
{
Base obj = DerivedFactory(arg); // copy (return by value)
return obj.GetValue();
}
This code contains an object slicing error: The stack space for obj is only as large as an instance of class Base; when DerivedFactory returns an object of a derived class which has some additional members, they will not be copied into obj which renders obj invalid and unusable as a derived object (and quite possibly even unusable as a base object.)
Summing up, there is a class of polymorphic behaviour that cannot be achieved with stack objects in any straightforward way.
Of course any completely constructed derived object, wherever it is stored, can act as a base object, and therefore act polymorphically. This simply follows from the is-a relationship that objects of inherited classes have with their base class.
Having read it I think the point is (especially given the second sentence about copy-semantics) that universal base class is useless for objects handled by value, so it would naturally lead to more handling via reference and thus more memory allocation overhead (think template vector vs. vector of pointers).
So I think he meant that the objects would have to be allocated separately from any structure containing them and that it would have lead to many more allocations on heap. As written, the statement is indeed false.
PS (ad Captain Giraffe's comment): It would indeed be useless to have function
f(object o)
which means that generic function would have to be
f(object &o)
And that would mean the object would have to be polymorphic which in turn means it would have to be allocated separately, which would often mean on heap, though it can be on stack. On the other hand now you have:
template <typename T>
f(T o) // see, no reference
which ends up being more efficient for most cases. This is especially the case of collections, where if all you had was a vector of such base objects (as Java does), you'd have to allocate all the objects separately. Which would be big overhead especially given the poor allocator performance at time C++ was created (Java still has advantage in this because copying garbage collector are more efficient and C++ can't use one).
Bjarne's statement is not correct.
Objects, that is instances of a class, become potentially polymorphic by adding at least one virtual method to their class declaration. Virtual methods add one level of indirection, allowing a call to be redirected to the actual implementation which might not be known to the caller.
For this it does not matter whether the instance is heap- or stack-allocated, as long as it is accessed through a reference or pointer (T& instance or T* instance).
One possible reason why this general assertion slipped onto Bjarne's web page might be that it is nonetheless extremely common to heap-allocate instances with polymorphic behavior. This is mainly because the actual implementation is indeed not known to the caller who obtained it through a factory function of some sort.
I think he was going along the lines of not being able to store it in a base-typed variable. You're right in saying that you can store it on the stack if it's of the derived type because there's nothing special about that; conceptually, it's just storing the data of the class and it's derivatives + a vtable.
edit: Okay, now I'm confused, re-looking at the example. It looks like you may be right now...
I think the point is that this is not "really" polymorphic (whatever that means :-).
You could write your test function like this
template<class T>
void test(T& obj)
{
obj.f();
}
and it would still work, whether the classes have virtual functions or not.
Polymorphism without heap allocation is not only possible but also relevant and useful in some real life cases.
This is quite an old question with already many good answers. Most answers indicate, correctly of course, that Polymorphism can be achieved without heap allocation. Some answers try to explain that in most relevant usages Polymorphism needs heap allocation.
However, an example of a viable usage of Polymorphism without heap allocation seems to be required (i.e. not just purely syntax examples showing it to be merely possible).
Here is a simple Strategy-Pattern example using Polymorphism without heap allocation:
Strategies Hierarchy
class StrategyBase {
public:
virtual ~StrategyBase() {}
virtual void doSomething() const = 0;
};
class Strategy1 : public StrategyBase {
public:
void doSomething() const override { std::cout << "Strategy1" << std::endl; }
};
class Strategy2 : public StrategyBase {
public:
void doSomething() const override { std::cout << "Strategy2" << std::endl; }
};
A non-polymorphic type, holding inner polymorphic strategy
class A {
const StrategyBase* strategy;
public:
// just for the example, could be implemented in other ways
const static Strategy1 Strategy_1;
const static Strategy2 Strategy_2;
A(const StrategyBase& s): strategy(&s) {}
void doSomething() const { strategy->doSomething(); }
};
const Strategy1 A::Strategy_1 {};
const Strategy2 A::Strategy_2 {};
Usage Example
int main() {
// vector of non-polymorphic types, holding inner polymorphic strategy
std::vector<A> vec { A::Strategy_1, A::Strategy_2 };
// may also add strategy created on stack
// using unnamed struct just for the example
struct : StrategyBase {
void doSomething() const override {
std::cout << "Strategy3" << std::endl;
}
} strategy3;
vec.push_back(strategy3);
for(auto a: vec) {
a.doSomething();
}
}
Output:
Strategy1
Strategy2
Strategy3
Code: http://coliru.stacked-crooked.com/a/21527e4a27d316b0
Let's assume we have 2 classes
class Base
{
public:
int x = 1;
};
class Derived
: public Base
{
public:
int y = 5;
};
int main()
{
Base o = Derived{ 50, 50 };
std::cout << Derived{ o }.y;
return 0;
}
The output will be 5 and not 50. The y is cut off. If the member variables and the virtual functions are the same, there is the illusion that polymorphism works on the stack as a different VTable is used. The example below illustrates that the copy constructor is called. The variable x is copied in the derived class, but the y is set by the initialization list of a temporary object.
The stack pointer has increased by 4 as the class Base holds an integer. The y will just be cut off in the assignment.
When using Polymorphism on the heap you tell the new allocator which type you allocate and by that how much memory on heap you need. With the stack this does not work. And neither memory is shrinking or increasing on the heap. As at the time of initialization you know what you're initializing and exact this amount of memory is allocated.
Related
Suppose that we have a simple struct:
struct RefCounters {
size_t strong_cnt;
size_t weak_cnt;
RefCounters() : strong_cnt(0), weak_cnt(0) {}
};
From implementation point, the destructor RefCounters::~RefCounters should do nothing, since all its members have primitive type. This means that if an object of this type is destroyed with explicit call of destructor (but its memory is not deallocated), then we would be able to work with its members normally after the object is dead.
Now suppose that we have some more classes derived from RefCounters. Suppose that RefCounters is present exactly once among base classes of Derived class. Suppose that destructor is called explicitly for an object of class Derived, but its memory is not deallocated. Is it OK to access members strong_cnt and weak_cnt after that?
From implementation point, it should be OK, at least when there is no virtual inheritance involved. Because Derived* can be statically cast to RefCounters* (adding compile-time constant offset to address), and the memory of RefCounters should not be touched by destructor of Derived class.
Here is a code sample:
struct RefCounted : public RefCounters {
virtual ~RefCounted() {}
};
struct Base : public RefCounted {
int val1;
virtual void print();
};
struct Derived : public Base {
std::string val2;
virtual void print();
};
Derived *pDer = new Derived();
pDer->~Derived(); //destroy object
pDer->strong_cnt++; //modify its member
std::cout << pDer->strong_cnt << pDer->weak_cnt << "\n";
Is such code considered undefined behavior by C++ standard? Is there any practical reason why it can fail to work? Can it be made legal by minor changes or adding some constraints?
P.S. Supposedly, such code sample allows to make intrusive_ptr + weak_ptr combo, such that weak_ptr can be always obtained from an object pointer if at least one weak_ptr is still pointing at it. More details in this question.
I believe that your approach is bad. There is a nice link in comments that shows debate about the details of the standard. Once there is a debate there is good chance that different compilers will implement this detail differently. Even more. The same compiler may change its implementation from one version to another.
The more you use various dark corners, the bigger is the chance that you will meet with problems.
Bottom line. What are willing to achieve? Why can't you do this using ordinary C++ language features?
I have got problem with passing inherited class type as argument to method that takes its base class type.
class Base {...}
class Derived : public Base {...}
class Container {
vector<Base*> cont; //1
public:
void addToCont(Base x) { //2
cont.push_back(&x);
}
}
int main() {
Container c;
c.addToCont(Derived(p1,p2)); //3
}
1) I suppose I need to have container of pointers to objects to keep it working
2) Here is error in conversion from Derived to Base
3) I am not supposed to change this call. I tried
Derived d(p1,p2);
c.addToCont(d);
with
addToCont(Base& x)
and it worked for me.
My problem is that I've got 3 derived classes and I don't want to overload the add method 3 times. I guess I will have to add some virtual method or some type-casting to those classes, but I couldn't find anything about that. I am novice in inheritance and quite confused of this. Thanks for all your help.
Some notes:
Must use a vector of pointers to the Base, so that you can handle objects from the hierarchy. Goes without saying that you're probably better off with using some kind of smart pointer instead of raw pointers, but that goes in preferences and how much you love risk.
Using void addToCont(Base x) is wrong because even if you were only adding a Base object, you will be adding a pointer to a local variable (the pass-by-value parameter)
Using void addToCont(Base &x) the way you do it with a local Derived d is wrong too, for the same reasons as before, as soon as d goes out of scope, you're left with a dangling pointer stored in the pointer
Calling addToCont(Derived(...)) passes a temporary object. That must be taken into account when you think about your memory management.
Not sure why you see a need for overloading addToCont for all Derived classes, that's not what you did on void addToCont(Base &x)
The solution (if you keep to the raw pointers) is to do void addToCont(Base *x) there you can pass a pointer to Base or to any Derived. Again, you must be mindful about the memory management. You're Derived object probably needs to be allocated with a new Derived(...) and you must watch about who owns it, and who has responsibility for deleting it (for example, when the Container object is destroyed).
You probably should remember to make virtual the destructor of Base, because you will be destroying Derived objects from Base pointers, and if the destructor is not virtual, the object will only be partially destroyed.
If addToCont(Derived(...)) call is absolutely required, then you might want to consider to use the void addToCont(Base &x) defininition.... but them, you must clone the object before inserting it into the vector:
void addToCont(const Base &x) { //2
cont.push_back(x.clone());
}
But then.. you need a virtual Base *clone() const method to be implemented (at least) in the Derived classes, that will produce a Base pointer with an exact copy of the Derived object, involving extra copies of the objects and extra cloning...
Derived classes are only "possible to use" when they are either references or pointers. If you convert a class to a base-class without a reference or pointer, you won't be able to use it as a derived class later.
If you are actually storing pointers in your container, then I would make it explicit, so:
class Container {
vector<Base*> cont;
public:
void addToCont(Base* x) {
cont.push_back(x);
}
~Container()
{
for(auto a : cont)
{
delete a;
}
}
}
And in main:
Container c;
c.addToCont(new Derived(p1,p2));
Note that in your original code, the Derived(p1, p2) will get destroyed again just after call to addToCont(...), so your array would be pointing to a "dead" element of the Derived class. Which was probably not what you actually wanted (since it's undefined behaviour to ever use that element, and building up a container full of useless elements is pretty pointless)
I'm pretty sure this is dangerous code. However, I wanted to check to see if anyone had an idea of what exactly would go wrong.
Suppose I have this class structure:
class A {
protected:
int a;
public:
A() { a = 0; }
int getA() { return a; }
void setA(int v) { a = v; }
};
class B: public A {
protected:
int b;
public:
B() { b = 0; }
};
And then suppose I want to have a way of automatically extending the class like so:
class Base {
public:
virtual ~Base() {}
};
template <typename T>
class Test: public T, public Base {};
One really important guarantee that I can make is that neither Base nor Test will have any other member variables or methods. They are essentially empty classes.
The (potentially) dangerous code is below:
int main() {
B *b = new B();
// dangerous part?
// forcing Test<B> to point to to an address of type B
Test<B> *test = static_cast<Test<B> *>(b);
//
A *a = dynamic_cast<A *>(test);
a->setA(10);
std::cout << "result: " << a->getA() << std::endl;
}
The rationale for doing something like this is I'm using a class similar to Test, but in order for it to work currently, a new instance T (i.e. Test) has necessarily be made, along with copying the instance passed. It would be really nice if I could just point Test to T's memory address.
If Base did not add a virtual destructor, and since nothing gets added by Test, I would think this code is actually okay. However, the addition of the virtual destructor makes me worried that the type info might get added to the class. If that's the case, then it would potentially cause memory access violations.
Finally, I can say this code works fine on my computer/compiler (clang), though this of course is no guarantee that it's not doing bad things to memory and/or won't completely fail on another compiler/machine.
The virtual destructor Base::~Base will be called when you delete the pointer. Since B doesn't have the proper vtable (none at all in the code posted here) that won't end very well.
It only works in this case because you have a memory leak, you're never deleting test.
Your code produces undefined behaviour, as it violates strict aliasing. Even if it did not, you are invoking UB, as neither B nor A are polymorphic classes, and the object pointed to is not a polymorphic class, therefore dynamic_cast cannot succeed. You're attempting to access a Base object that does not exist to determine the runtime type when using dynamic_cast.
One really important guarantee that I can make is that neither Base
nor Test will have any other member variables or methods. They are
essentially empty classes.
It's not important at all- it's utterly irrelevant. The Standard would have to mandate EBO for this to even begin to matter, and it doesn't.
As long as you perform no operations with Test<B>* and avoid any magic like smart pointers or automatic memory management, you should be fine.
You should be sure to look for obscured code like debug prints or logging that will inspect the object. I've had debuggers crash on me for attempting to look into a value of a pointer set up like this. I will bet this will cause you some pain, but you should be able to make it work.
I think the real problem is maintenance. How long will it be before some developer does an operation on Test<B>*?
Hallo,
I come from a C# background and don't have a lot of C++ experience. To produce clean code I try to separate implementation and interfaces and use inheritance when possible. And when I tried to apply typical C# concepts to C++ I ran into a problem that I've been unable to resolve so far. I assume that this is probably trivial for an experienced C++ programmer but it has been driving me crazy for quite a while.
First I declare a base class (it contains no logic at the moment but it will in the future)
class PropertyBase : public IProperty
{
};
Then I define an interface for the Properties
class IProperty
{
public:
virtual ~IProperty() {};
virtual PropertyBase correct(const ICorrector &corrector) = 0;
virtual PropertyBase joinWith(const PropertyBase &partner, const IRecombinator &recombinator) = 0;
};
This is where the problem comes in: The compiler returns errors for the two virtual functions saying that it is not allowed to declare a function that returns an abstract class. Of course I don't want to return an object of the type PropertyBase. I want to declare other classes that inherit from PropertyBase that return an instance of themselves.
Now I've read that a possible way around it is to modify IProperty like this to return pointers:
class IProperty
{
public:
virtual ~IProperty() {};
virtual PropertyBase* correct(const ICorrector &corrector) = 0;
virtual PropertyBase* joinWith(const PropertyBase &partner, const IRecombinator &recombinator) = 0;
};
However I would like to avoid this if possible to prevent memory leaks. It would be great if someone would have a better idea to deal with this problem.
Thank you very much
If you're afraid of memory leaks, switch to smart pointers. That has the additional benefit of being self-documenting wrt. ownership of the returned object.
class IProperty
{
public:
virtual ~IProperty() {};
virtual std::unique_ptr<PropertyBase> correct(const ICorrector &) = 0;
virtual std::unique_ptr<PropertyBase> joinWith(const PropertyBase &,
const IRecombinator &) = 0;
};
In your client code:
std::unique_ptr<PropertyBase> pb(property.correct(corrector));
// use pb and forget about it; smart pointers do their own cleanup
Or, if you want reference counting on the object:
std::shared_ptr<PropertyBase> pb(property.correct(corrector));
See MSDN docs for unique_ptr, shared_ptr.
This may not be the answer you're looking for, but it seems to me that you are a little confused about pointers and values in C++.
You have to return either a pointer, or a reference, in C++ if you want proper ad-hoc polymorphism. In this case, the compiler issued an error, because the base class was abstract. If instantiating an abstract class would be possible, it would have "holes" in it.
The thumb rule is: Whenever you have a class hierarchy, never return objects of such types by value. Suppose you have class Base { int x; }, and class Derived : public Base { int y; }. If you do this:
Base Function() { Derived d; return d; }
...
Base b = Function();
Then b will not be a value of class Derived "hiding behind" a Base. The value b WILL be Base. The compiler will "slice off" the differences between Derived and Base, and put it into b.
In C++, you will have to use pointers or references to facilitate ad-hoc polymorphism. References in C# is pretty much the same thing as pointers in C++, with the exception that you do not have to free the objects in C#, as the garbage collector will handle this for you.
There's nothing wrong with returning a pointer to an object. If you're worried about memory leaks, as you should be, the solution is to use smart pointers to store the returned pointer. The most flexible of these is shared_ptr from boost or the upcoming C++0x standard.
More generally, if you're going to be doing any serious amount of work in C++, getting comfortable with pointers and memory management is kind of essential. For in-depth coverage of that and other tricky aspects of C++, I strongly recommend the Effective C++ books by Scott Meyers and the Exceptional C++ books by Herb Sutter.
There is very easy solution to this problem. Use pointers or references for return values, but instead of returning ownership in the pointers, you should not return ownership.
For example:
class A : public Base
{
public:
Base *correct(const I &c)
{ p2 = do_something(c); return &p2; }
...
private:
A2 p2;
};
What makes this work is that you store the p2 inside the class and never pass ownership of the objects to outside of it. The function in the interface will not create new objects, but instead it'll just return existing one, configured to correct state based on function's parameters. This is a good alternative to the unique_ptr and shared_ptr solution which relies on heap allocation and creating new objects and passing them around.
Now the nice trick with this is that you need to list all possible types you want to return from your correct() function in the data members of the class. For example, if sometimes you would return different type, it'd look like this:
class B : public Base
{
public:
Base *correct(const I &c) {
switch(c.get_bool()) {
case false: p3 = do_something_else(c); return &p3;
case true: p4 = do_something(c); return &p4;
};
}
private:
B3 p3;
B4 p4;
};
But placing your objects p3 and p4 inside the current B object will solve this problem completely.
I was reading about Empty Base Optimization(EBO). While reading, the following questions popped up in my mind:
What is the point of using Empty class as base class when it contributes nothing to the derived classes (neither functionality-wise, nor data-wise)?
In this article, I read this:
//S is empty
class struct T : S
{
int x;
};
[...]
Notice that we didn’t lose any data or
code accuracy: when you create a
standalone object of type S, the
object’s size is still 1 (or more) as
before; only when S is used as base
class of another class does its memory
footprint shrink to zero. To realize
the impact of this saving, imagine a
vector that contains 125,000
objects. The EBO alone saves half a
megabyte of memory!
Does it mean that if we don't use "S" as base class of "T", we would necessarily consume double of megabyte of memory? I think, the article compares two different scenarios which I don't think is correct.
I would like to know a real scenario when EBO can proven to be useful.(means, in the same scenario, we would necessarily be at loss IF we don't use EBO!).
Please note that if your answer contains explanations like this :
The whole point is that an empty class has non-zero size, but when derived or deriving it can have zero size, then I'm NOT asking that, as I know that already. My question is, why would anyone derive his class from an empty class in the first place? Even if he doesn't derive and simply writes his class (without any empty base), is he at loss in ANY way?
EBO is important in the context of policy based design, where you generally inherit privately from multiple policy classes. If we take the example of a thread safety policy, one could imagine the pseudo-code :
class MTSafePolicy
{
public:
void lock() { mutex_.lock(); }
void unlock() { mutex_.unlock(); }
private:
Mutex mutex_;
};
class MTUnsafePolicy
{
public:
void lock() { /* no-op */ }
void unlock() { /* no-op */ }
};
Given a policy based-design class such as :
template<class ThreadSafetyPolicy>
class Test : ThreadSafetyPolicy
{
/* ... */
};
Using the class with a MTUnsafePolicy simply add no size overhead the class Test : it's a perfect example of don't pay for what you don't use.
EBO isn't really an optimization (at least not one that you do in the code). The whole point is that an empty class has non-zero size, but when derived or deriving it can have zero size.
This is the most usual result:
class A { };
class B { };
class C { };
class D : C { };
#include <iostream>
using namespace std;
int main()
{
cout << "sizeof(A) + sizeof(B) == " << sizeof(A)+sizeof(B) << endl;
cout << "sizeof(D) == " << sizeof(D) << endl;
return 0;
}
Output:
sizeof(A) + sizeof(B) == 2
sizeof(D) == 1
To the edit:
The optimization is, that if you actually do derive (for example from a functor, or from a class that has only static members), the size of your class (that is deriving) won't increase by 1 (or more likely 4 or 8 due to padding bytes).
The "Optimization" in the EBO means the case when you use base class can be optimized to use less memory than if you use a member of the same type. I.e. you compare
struct T : S
{
int x;
};
with
struct T
{
S s;
int x;
};
not with
struct T
{
int x;
};
If your question is why would you have an empty class at all (either as a member, or as a base), it is because you use its member functions. Empty means it has no data member, not that it does not have any members at all. Things like this are often done when programming with templates, where the base class is sometimes "empty" (no data members) and sometimes not.
Its used when programmers want to expose some data to client without increasing the client class size. The empty class can contain enums and typedefs or some defines which the client can use.The most judicious way to use such a class it it to,inherit such a class privately. This will hide the data from outside and wil not increase your class size.
There can be empty classes which do not have any member variables, but member functions (static or non static) which can act as utility classes, lets call this EmptyClass. Now we can have a case where we want to create a class (let's call it SomeClass) which have a containment kind of relation with EmptyClass, but not 'is-a' relation. One way is to create a member object of type EmptyClass in SomeClass as follows:
class EmptyClass
{
public:
void someFun1();
static int someUtilityFun2();
};
//sizeof(EmptyClass) = 1
class SomeClass
{
private:
EmptyClass e;
int x;
};
//sizeof(SomeClass) = 8
Now due to some alignment requirements compilers may add padding to SomeClass and its size is now 8 bytes. The better solution is to have a SomeClass derive privately from EmptyClass and in this way SomeClass will have access to all member functions of EmptyClass and won't increase the extra size by padding.
class SomeClass : private EmptyClass
{
private:
int x;
}
//sizeof(SomeClass) = 4
Most of the time, an empty base class is either used polymorphically (which the article mentions), as "tag" classes, or as exception classes (although those are usually derived from std::exception, which is not empty). Sometimes there is a good reason to develop a class hierarchy which begins with an empty base class.
Boost.CompressedPair uses the EBO to shrink the size of objects in the event that one of the elements is empty.
EASTL has a good explanation as to why they needed EBO, its also explained in-depth in the paper they link to/credit
EBO is not something the programmer influences, and/or the programmer would be punished for if (s)he chose not to derive from an empty base class.
The compiler controls whether for:
class X : emptyBase { int X; };
class Y { int x };
you get sizeof(X) == sizeof(Y) or not. If you do, the compiler implements EBO, if not, it doesn't.
There never is any situation where sizeof(Y) > sizeof(X) would occur.
The primary benefit I can think of is dynamic_cast. You can take a pointer to S and attempt to dynamic_cast it to anything that inherits from S- assuming that S offers a virtual function like a virtual destructor, which it pretty much must do as a base class. If you were, say, implementing a dynamically typed language, you may well wish or need for every type to derive from a base class purely for the purposes of type-erased storage, and type checking through dynamic_cast.