Using Private

September 25, 2009

My last blog post generated a really interesting comment from one of the folks on LinkedIn. He raised a couple of key issues that really got me to thinking. Eventually what I took from it all was that a Vector and a NormalizedVector are sort of two different things… and sort of the same thing. This post is a look at how to best express and manage this unusual situation.

First let’s consider the obvious part, how are they the same? Well they’re both vectors, so they should both support the kinds of things that vectors do, addition, cross products, dot products, etc etc. No surprises there, but how are they different? Well some of the things that make sense on a plain vector are meaningless on a normalized one. For example, SetLength is stupid, as are dividing and multiplying by a scalar. And if you need to call GetLength on a normalized vector then you’re doing something wrong.

My last post suggested a single template class that sort of ignored all these issues and just created one all-purpose vector that used template tricks to act like 2 vectors. You could happily call GetLength() on a NormalizedVector. The SetLength function existed for both, but would refuse to compile if you tried to call it on a NormalizedVector. While it was nice that it failed at compile time, it still left the interface with a function that didn’t exist, which is sort of sucky. So it became clear that I needed a new solution. Let’s look at the first 3 that sprung to mind.

Option 1: Two completely different classes. This was actually what I went with first. It’s old school and is easy to understand and create. You start with 2 headers and you fill them with 2 different classes. But of course then you have to try not to gag while you’re copying and pasting all the common code. CrossProduct, DotProduct, equality tests, etc etc. You just cut and paste and pray that if you find a bug in one you remember to fix it in the other. Not ideal.

Option 2: Composition. Stick all of the common stuff into one class called VectorCommonStuff and let each vector contain one of these. This is nice because the two vectors are different types, but it sucks because… well because the two vectors are completely different types. Plus you end up having to add an extra layer to get to the common code. So Vector::CrossProduct does nothing but call VectorCommonStuff::CrossProduct. I’m sure an optimizer could clean this up for you, but the code is still ugly and overly deep. Who else is sick and tired of having the debugger step into a one line function and then having to make it step in again?

Option 3: Inheritance. Good old fashioned polymorphism to save the day. Make yourself a BaseVector class which supports all the public stuff, then inherit from it for each vector. This fixes the problem of public functions that just call private functions, but now your two vectors really are the same thing. You open yourself up to creating functions that take BaseVector* and happily take either type of vector. In a way this is nice, but it defeats the purpose of creating separate types.

So what are we to do? Is there a way to combine the clean separation of composition with the common code base simplicity of inheritance? Well I ended up finding a solution that I’m very pleased with. I’m also very pleased to note that after 12 years as a professional C++ developer, I found a keyword that I had never seen before. That keyword is “using” and when you mix it with private inheritance you end up with a slick solution. For those (like me) who have never used private inheritance before, a refresher. As far as the child class is concerned, private inheritance works just like public inheritance, ie you have access to your parent’s public and protected members. However to the outside world you didn’t inherit from anything (and your parent’s public functions are not accessible). According to the docs I read, this is considered a “has-a” relationship, just like composition. In fact, by itself it offers us no real benefits over composition, you still have to create public functions that call your parent class’ functions. And that’s where the “using” keyword comes into play. You can use it to expose your parent’s functions to the outside world. Time for a simple example:

class VectorBase
{
protected:
    float GetXComponent();
};

class Vector
    : private VectorBase
{
public:
    using VectorBase::GetXComponent;
};

Do you see the magic? That “using” keyword makes the inherited GetXComponent() function public. So now I have exactly what I’m looking for. My two different vectors can privately inherit from a VectorBase. To the outside world they’re entirely different classes, which means I can write expressive code that specifically uses the kind I want. But inside the classes I can share common code in a clean, easy to maintain fashion. I can also expose shared code in one simple line.

I continue to love C++. Who would have thought that after so many years I’d still be finding out new things at the fundamental level? What do you think? Had any experience with these 2 concepts before? Did I miss something obvious or not so obvious? Feel free to comment and keep the conversation going.

posted by james wells at 3:11 pm

No Comments »

No comments yet.

RSS feed for comments on this post. TrackBack URL

Leave a comment