Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are C++ polymorphic classes without any functions possible?

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.

like image 911
Malvineous Avatar asked Aug 18 '12 11:08

Malvineous


People also ask

Is polymorphism possible without objects?

Languages that are not object-oriented provide forms of polymorphism which do not rely on inheritance (i.e parametric polymorphism). Some of this is possible in Java through generics.

Is polymorphism possible in C?

Polymorphism is possible in C language. Explanation: It is possible to implement polymorphism in C language, even though it doesn't support class. We can use structures and then declare pointers which in turn points to some function.

Do you need pointers for polymorphism?

(*) Genericity, the type of polymorphism provided by templates, doesn't need pointers nor references.

What makes a class polymorphic?

A class that declares or inherits a virtual function is called a polymorphic class. Note that despite of the virtuality of one of its members, Polygon was a regular class, of which even an object was instantiated ( poly ), with its own definition of member area that always returns 0.


1 Answers

If you add a virtual function, the classes will get a vtable so that dynamic_cast works. 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, Text and Item. Item inherits from the three former and defines no functions itself. You provide "reference implementations" for the first three interfaces. The "reference impl." for Item has three data members (the ref. impl. of the first three interfaces) and forwards to these implementations. Now you can use e.g. Position wherever you need something that has a position, without having to know what exactly it is. dynamic_cast works, too.

You could also define an interface ItemBase with no virtual methods and have Position, Speed and Text inherit 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 for virtual inheritance, I think...

like image 114
krlmlr Avatar answered Sep 29 '22 16:09

krlmlr