Re: Some thoughts on polymorphism
On May 2, 10:43 am, chsal...@gmail.com wrote:
I've been programming in C++ for a little over 2 years, and I still
find myself wondering when I should use polymorphism.
Some people claim that polymorphism is such an integral part of C++,
that anybody who doesn't use it might as well just program in plain
C. I totally disagree with this, because I think C++ has a lot of
great features apart from polymorphism, such as the ability to
organize code into classes, code reuse through inheritance, templates,
template specialization, etc.
Still, most people promote C++ and OO in general because of
polymorphism. But for some reason, I find the idea of defining lots
of little classes that inherit from a base class to be a bit
overreaching just to do something that essentially boils down to a
function pointer.
Take the following example:
Recently I was working on a project where a server would interpret
various commands issued by a client. There were about 25 different
possible commands. Each command the client issues should cause the
server to respond in a different way.
So what's the best way to implement this in C++?
The first thing that came to mind was a typical C approach: make a
hash table of key words (commands), and associate each key with a
function pointer. This is simple and extremely efficient. But since
I'm programming in C++ I feel compelled to explore more OOish
alternatives. Also, the server program itself was a class, so I'd
need to have the hash table store pointers to functions which are not
part of the class, which kind of breaks the whole design. (Unless I
use dreaded member function pointers - which __nobody__ ever uses, and
which entail considerable overhead to dereference.)
So, I thought: how about polymorphism? I could create an abstract
base class "command", with a single virtual function, and then make 25
little classes which inherit from it. Then I could just have a
generic execute() function, like:
void execute_command(Command* c)
{
c->dosomething();
}
This seems like it would be the standard C++ way of doing this.
Still, there's something about it that just seems ridiculous. I
define 25 classes, just so I can pick between functions dynamically.
On top of that, doing this the old fashioned way (a table of plain
function pointers) is more efficient, since it doesn't involve the
vtable.
For some reason, I don't feel like C++ offers an elegant solution to
this problem. Am I just being too picky? Or does anyone agree?
Comments, thoughts, suggestions, would be appreciated.
I write stuff with a similar requirement a lot. There are all sorts of
dynamic plug-in routines that need to be run at various times
depending on a whole host of factors. As you suggest the standard way
that I implement this is as some sort of function lookup. Does that
mean C++ is pointless? I think that's looking at it in the wrong way.
One thing that I keep repeating in different ways is that we should be
dogmatic about our results, not our methods. We need to use the right
solution for a given problem, not the one that we feel we are
"supposed" to use. The truth is that C++ opens more ways of solving a
problem than any other language I've used. If a table of function
pointers is the right way to solve this problem then C++ lets you do
it.
C++ also lets you abstract out the table and the lookups into a
templated class so that it can be re-used. I've done this in FOST.3
because we use it so often for handling plug-ins and configurable
items. Now I can set up a new plug-in location with just a couple of
lines of code and the registration of the plug-ins is even thread-safe
so it doesn't matter when in the application's lifetime they are
loaded.
But what do you put in the table? You could store raw function
pointers, but it is probably a lot more flexible if you store a
boost::function0< void > because you can then store raw function
pointers, but you can also bind parameters (currying) to the functions
so that you can use the same function and configure the differences
more easily.
Sure, this feels more like functional programming (because that's
exactly what it is) than OO programming, but again, we use our tool to
give us the appropriate solution.
And you also get the benefit of classes when they are the right
abstraction. The only other languages I've come across that are this
flexible are the LISP family, but for some reason they're much less
popular (probably because they don't play as nicely with other
languages as C++ does).
In C++ you have an extraordinarily powerful tool that will allow you
to write the correct solution in the best way. Don't listen to anybody
who tells you that C++ is all about objects and certainly don't listen
to anybody who tells you that OO is about sub-classing (but that's a
story for another time).
The function table is just as OO as the classes in C++ are. It's just
that you're writing your own message dispatcher rather than using one
of the built in ones. That's cool.
K