I am trying to create some classes which only contain data members (no functions) but I would like them to be polymorphic – by which I mean I will be passing around the objects by a pointer to the base class, and I need the ability to dynamic_cast them to a specific derived type (and have the resulting value be NULL if the instance is not of the given type.)
By way of example, I have an item:
struct Item {
int x, y;
}
I also have an item which moves, and another which contains text:
struct MovingItem: virtual public Item {
int speedX, speedY;
}
struct TextItem: virtual public Item {
std::string text;
}
Presumably I have to use virtual inheritance above, because I also want an item that moves and has text, but I only want the one set of coordinates from the top-level Item:
struct MovingTextItem: virtual public MovingItem, virtual public TextItem {
}
These can all be defined correctly, but when I try to dynamic_cast an Item * to see what type it is, my compiler complains that the source types aren’t polymorphic.
void example(Item *i) {
MovingTextItem *mti = dynamic_cast<MovingTextItem *>(i); // error!
}
This would work if I reimplemented the whole thing using virtual functions instead of data members, but this seems like a waste as I never need to override anything.
The only workaround I can think of is to add a type member to the base Item class, and check that instead of using dynamic_cast, and if it’s of the correct type then use static_cast instead. (The drawback there being I have to know about all object types somewhere so the assigned type values don’t conflict.)
Is this the best solution, or is there another way?
Clarification
For arguments’ sake, imagine I am writing each object type to a file. MovingItem goes to one file, TextItem goes to a different file, and MovingTextItem goes to both files. So having a base class which implements every interface won’t work, unless I can somehow tell which interfaces are in use so they get written to the correct files.
If you add a virtual function, the classes will get a vtable so that
dynamic_castworks. A no-op virtual destructor will do. (As Torsten points out, this even might be necessary in your case as you have non-POD members.)However, from my own experience (and I have been resisting this for years!) I would strongly advise against inheritance in this particular case. Use aggregation instead. Prefer composition over inheritance? You may have to create a couple of forwarders, but the flexibility gained by this pays off (in terms of being able to later change implementations without influencing the whole system).
Think of an item that has a speed and, in addition, a text and a position, instead of being an item that somehow has speed and text and by some magic inherits the position. What if you later want an item that has speed but no known position?
To achieve your results in an aggregation scenario, define “interfaces” that constitute the contract concerning a particular feature. No need for virtual inheritance, too: The “interfaces” are just classes with only pure virtual functions. See also: What does it mean to "program to an interface"? (Another important rule if you want maintainable software.)
Example
You could define four “interfaces” (classes with only pure virtual functions):
Position,Speed,TextandItem.Iteminherits from the three former and defines no functions itself. You provide “reference implementations” for the first three interfaces. The “reference impl.” forItemhas three data members (the ref. impl. of the first three interfaces) and forwards to these implementations. Now you can use e.g.Positionwherever you need something that has a position, without having to know what exactly it is.dynamic_castworks, too.You could also define an interface
ItemBasewith no virtual methods and havePosition,SpeedandTextinherit from this interface. This will allow you to access all featurettes through the same base type and dynamically test for the availability of a subinterface. Still no need forvirtualinheritance, I think…