You can do what you want with the proper theoretical operation which is NOT polymorphism, but unification. Most people have no idea what a sum type (discriminated union) is and what it is for which is why they consistently abuse inheritance, which is entirely unrelated.
Unions are more popular in C, for example X-Windows event messages are union based, because they're broken in C++.
A union is the correct way to represent heterogeneous data types as a single type, hence the name unification: it unifies all the components into a single type. Unions always have a finite known number of components, functions using unions invariably use a switch on the discriminant to select the right handler code.
OOP cannot provide unification: it provides subtyping.
Templates provide something quite different again: parametric polymorphism.
All three concepts are quite distinct in both theory and practice. Subtyping OOP style turns out to be the least useful because what it can represent is heavily restricted, however those restrictions do permit dynamic dispatch to an open set of subtypes, which is very nice if it applies to your problem.
So now it is clear, in your array, all you need to put is a union of all your classes, and your problem goes away.
Only .. the classes have to be POD types in C++ at present due to an unprincipled restriction. So the best solution is to use a union of raw C functions, since C function pointers are PODs.
Something like:
enum tag {tag_X, tag_Y};
struct X { int x; };
void px(X a) { cout << a.x; }
struct PX { tag t; X a; void (*p)(X); };
struct Y { double x; };
void py(Y a) { cout << a.x; };
struct PY {tag t; Y a; void (*p)(Y); };
union XY { PX anX; PY anY; };
PX x1 = { tag_X, { 1 }, px };
PY y1 = { tag_Y, { 1.0 }, py };
XY xy1.anPX = x1;
XY xy2.anPy = x2;
XY xys[2] = {xy1, xy1};
xy = xys[0];
switch (xy.anPX.tag) { // hack
case tag_X: xy.anPX.p (xy.PX.x); break;
case tag_Y: xy.anPY.p (xy.PY.x); break;
}
If you think this is ugly, you're right: C and C++ are brain dead. Another solution is to use a tag and a pointer which is cast to a void*, then use the tag to cast to the required type: this is much easier but requires heap allocation of the data and hence you have a memory management issue. Another alternative is Boost variant type (which automates some of the housekeeping but is still very ugly).
Here's similar code in Ocaml:
type xy = X of int | Y of double
let print u =
match u with
| X x -> print_int x
| Y x -> print_double x
in
print (X 1);
print (Y 2.0)
In this code the X and Y are the tags of the C code above, they're called type constructors because they construct an xy type out of an int or a double (resp.). The match expression there is just a switch with automatic selection of the right component type and scoping used to ensure you can't refer to the wrong component (as you could in the C code), also there's no break, match handlers don't drop thru, and the memory management is done by a garbage collector.