Polymorphism & Pointers to Arrays

Polymorphism & Pointers to arrays

You can't treat arrays polymorphically, so while new B[100] creates an array of B objects and returns a pointer to the array - or equivalently the first element of the array - and while it is valid to assign this pointer to a pointer to a base class, it is not valid to treat this as a pointer into an array of A objects.

The principal reason that you can't is that (typically) derived objects are a different size to their base classes, so attempting to access the array as an array of base class objects will not use the correct offset to get a pointer to the next base class subobject of the next member of the derived class array.

Why does polymorphism not apply on arrays in C++?

You get undefined behavior because operator delete[] has no idea what kind of object is stored in the array, so it trusts the static type to decide on offsets of individual objects. The standard says the following:

In the second alternative (delete array) if the dynamic type of the object to be deleted differs from its static type, the behavior is undefined.

The array's static type needs to match the element type that you use for the allocation:

Derived* p = new Derived[4]; // Obviously, this works

This Q&A goes into more details on the reason why the standard has this requirement.

As far as fixing this behavior, you need to create an array of pointers, regular or smart (preferably smart to simplify memory management).

Array of polymorphic objects

In very simple terms:

  • unique_ptr is the owner of the object. It manages the lifetime of the owned object

  • reference_wrapper wraps a pointer to an object in memory. It does NOT manage the lifetime of the wrapped object

You should create an array of unique_ptr (or shared_ptr) to guarantee the release of the object when it's not needed anymore.

C++ polymorphism of a object in an array

As others have pointed out, the convenient and common way doesn't work like that. Fixing it results in code which is at odds with the restrictions of your target platform. You can, however, emulate polymorphism differently in several different ways.

You can segregate the objects by type like this:

const Triangle tris[] = {tri1, tri2, ...};
const Rectangle rects[] = {rect1, rect2, ...};
// for correct order, if needed
const Shape * const shapes[] = {&tris[0], &rects[2], &rects[0], ...}:

You still need to make all methods (that behave differently for the various types) virtual, and you pay an extra pointer (two if you count the vtable pointer, which would be a bit unfair) per object.
You could also remove everything virtual in favor of an explicit tag:

enum ShapeKind { Triangle, Rectangle, Pentagon };
struct Shape {
ShapeKind kind;
int sides;
...
};

Use a union if the various subclasses need very different member data.
This has numerous severe restrictions and leads to rather ugly code, but can work well. For example, you need know your hierarchy up front and the subclasses need to be roughly the same size. Note that this is not necessarily faster than the virtual alternative, but when it's applicable it can take less space (a byte instead of a vtable pointer) and make introspection leaner.

Polymorphism and array of pointers (C++)

Add should take a pointer:

void Add(CControl * newElement){                       
elements[elemCnt++] = newElement;
}

then you can call it like this

c.Add( new Button(...) ); 
c.Add( new Input(...) );

If you really cannot change the calling code, you need to somehow create a copy of the temporary.
E.g. by implementing a virtual Clone method in CControl, Input, Button an call it in Add.

void Add(const CControl & newElement){                        
elements[elemCnt++] = newElement.Clone();
}

polymorphism c++, trying to access member functions of classes that are derived from abstract base class

No, what you are trying to do is not polymorphism. It is actually the exact opposite of polymorphism.

Polymorphism is using only your base class interface to manipulate any of your derived classes, including those that are not written yet.

For example, if you want your items to have titles, you define a virtual (possibly pure) method getTitle() in your base class, and implement it in your derived classes. This way you can get a title of any item in your collection without knowing or caring about its exact type.



Related Topics



Leave a reply



Submit