Inheriting from a template class in c++

dtech picture dtech · Jan 10, 2012 · Viewed 149.1k times · Source

Let's say we have a template class Area, which has a member variable T area, a T getArea() and a void setArea(T) member functions.

I can create an Area object of a specific type by typing Area<int>.

Now I have a class Rectangle that inherits the Area class. Since Rectangle itself is not a template, I cannot type Rectangle<int>.

How do I specialize the inherited Area type for Rectangle objects?

EDIT: Sorry, I forgot to clarify - my questions is whether it is possible to inherit Area without specializing it, so it is not inherited as Area of ints but as Area Rectangle can specialize the types for.

Answer

celtschk picture celtschk · Jan 10, 2012

For understanding templates, it's of huge advantage to get the terminology straight because the way you speak about them determines the way to think about them.

Specifically, Area is not a template class, but a class template. That is, it is a template from which classes can be generated. Area<int> is such a class (it's not an object, but of course you can create an object from that class in the same ways you can create objects from any other class). Another such class would be Area<char>. Note that those are completely different classes, which have nothing in common except for the fact that they were generated from the same class template.

Since Area is not a class, you cannot derive the class Rectangle from it. You only can derive a class from another class (or several of them). Since Area<int> is a class, you could, for example, derive Rectangle from it:

class Rectangle:
  public Area<int>
{
  // ...
};

Since Area<int> and Area<char> are different classes, you can even derive from both at the same time (however when accessing members of them, you'll have to deal with ambiguities):

class Rectangle:
  public Area<int>,
  public Area<char>
{
  // ...
};

However you have to specify which classed to derive from when you define Rectangle. This is true no matter whether those classes are generated from a template or not. Two objects of the same class simply cannot have different inheritance hierarchies.

What you can do is to make Rectangle a template as well. If you write

template<typename T> class Rectangle:
  public Area<T>
{
  // ...
};

You have a template Rectangle from which you can get a class Rectangle<int> which derives from Area<int>, and a different class Rectangle<char> which derives from Area<char>.

It may be that you want to have a single type Rectangle so that you can pass all sorts of Rectangle to the same function (which itself doesn't need to know the Area type). Since the Rectangle<T> classes generated by instantiating the template Rectangle are formally independent of each other, it doesn't work that way. However you can make use of multiple inheritance here:

class Rectangle // not inheriting from any Area type
{
  // Area independent interface
};

template<typename T> class SpecificRectangle:
  public Rectangle,
  public Area<T>
{
  // Area dependent stuff
};

void foo(Rectangle&); // A function which works with generic rectangles

int main()
{
  SpecificRectangle<int> intrect;
  foo(intrect);

  SpecificRectangle<char> charrect;
  foo(charrect);
}

If it is important that your generic Rectangle is derived from a generic Area you can do the same trick with Area too:

class Area
{
  // generic Area interface
};

class Rectangle:
  public virtual Area // virtual because of "diamond inheritance"
{
  // generic rectangle interface
};

template<typename T> class SpecificArea:
  public virtual Area
{
  // specific implementation of Area for type T
};

template<typename T> class SpecificRectangle:
  public Rectangle, // maybe this should be virtual as well, in case the hierarchy is extended later
  public SpecificArea<T> // no virtual inheritance needed here
{
  // specific implementation of Rectangle for type T
};