templates: parent class member variables not visible in inherited class

An extended comment on UncleBens' answer.

It is always good to keep in mind that class templates are not classes. They are templates. One way to look at it: In C++, classes are not objects. You need to instantiate a class to create an object. A similar concept applies to class templates and classes. Just as class instantiation creates an object, class template instantiation creates a class.

Until the template is instantiated, that inheritance relationship you set up between unorderedArrayListType and arrayListType doesn't quite exist. The compiler does not know if you are going to define a partial template instantiation of arrayListType that doesn't have length and list as data members. You need to give the compiler a hand in your unorderedArrayListType by using this->length and this->list or some other construct that tells the compiler that you do expect these to be data members.

Suppose you use this->length in unorderedArrayListType, and suppose that someone comes along and writes a partial template instantiation of arrayListType<FooType> that does not have length and list as data members. Now instantiating an unorderedArrayListType<FooType> will result in compile time error. But since you aren't going to do that (you aren't going to do that, are you?), using this->length will be OK.


I would try two things:

1. Use this-> (which is generally a good idea to do with templates).

template <class elemType>
void unorderedArrayListType<elemType>::insertAt(int location, const elemType& insertItem)
{
    for(int i = this->length; i > location; i--)
        this->list[i] = this->list[i - 1];

    this->list[location] = insertItem;
    this->length++;
}

2. Typedef the parent and use it when accessing the parent members:

template <class elemType>
class unorderedArrayListType: public arrayListType<elemType>
{
    typedef arrayListType<elemType> Parent;
    ...
}

template <class elemType>
void unorderedArrayListType<elemType>::insertAt(int location, const elemType& insertItem)
{
    for(int i = Parent::length; i > location; i--)
        Parent::list[i] = Parent::list[i - 1];

    Parent::list[location] = insertItem;
    Parent::length++;
}

This is because the template parent of a template class is not instantiated during the compilation pass that first examines the template. These names appear to be non-dependent on the particular template instantiation, and therefore the definitions need to be available. (If you never look at the definition of arrayListType, then reading the code of unorderedArrayListType it would appear the list and length need to be some sort of globals.)

You'll need to tell the compiler explicitly that the names are in fact dependent on the instantiation of the parent.

One way, using this-> before all the inherited names: this->list, this->length.

Another way, using declarations: using arrayListType<elemType>::length; etc (for example in the private section of the derived class).


A FAQ entry on this: https://isocpp.org/wiki/faq/templates#nondependent-name-lookup-members