Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

templates: parent class member variables not visible in inherited class

I have the following 4 files:

  1. arrayListType.h: Declare and define arrayListType class as a template
  2. unorderedArrayListType.h: Inherited from arrayListType class and Declares and defines unorderedArrayListType as a template.
  3. main1.cpp: Test program to test unorderedArrayListType class.
  4. Makefile

I get a compile error saying when accessing the protected variables of arrayListType in unorderedArrayListType for example: "length not declared in this scope", "list not declared in this scope", where length and list are protected variables in arrayListType class.

The following are the codes:
arrayListType.h

#ifndef H_arrayListType   #define H_arrayListType  #include <iostream>  using namespace std;  template <class elemType> class arrayListType {  public:      const arrayListType<elemType>&operator=(const arrayListType<elemType>&);      bool isEmpty() const;     bool isFull() const;     int listSize() const;     int maxListSize() const;     void print() const;     bool isItemAtEqual(int location, const elemType& item) const;     virtual void insertAt(int location, const elemType& insertItem) = 0;     virtual void insertEnd(const elemType& insertItem) = 0;     void removeAt(int location);     void retrieveAt(int location, elemType& retItem) const;     virtual void replaceAt(int location, const elemType& repItem) = 0;     void clearList();     virtual int seqSearch(const elemType& searchItem) const;     virtual void remove(const elemType& removeItem) = 0;      arrayListType(int size = 100);     arrayListType(const arrayListType<elemType>& otherList);      virtual ~arrayListType();   protected:      elemType *list;     int length;     int maxSize; };   template <class elemType> bool arrayListType<elemType>::isEmpty() const {     return (length == 0); }  // remaining non-virtual functions of arrayListType class  #endif 

unorderedArrayListType.h

#ifndef H_unorderedArrayListType #define H_unorderedArrayListType  //#include <iostream> #include "arrayListType.h"  //using namespace std;  template <class elemType> class unorderedArrayListType: public arrayListType<elemType> {  public:      void insertAt(int location, const elemType& insertItem);     void insertEnd(const elemType& insertItem);     void replaceAt(int location, const elemType& repItem);     int seqSearch(const elemType& searchItem) const;     void remove(const elemType& removeItem);      unorderedArrayListType(int size = 100); };  template <class elemType> void unorderedArrayListType<elemType>::insertAt(int location, const elemType& insertItem) {     for(int i = length; i > location; i--)         list[i] = list[i - 1];      list[location] = insertItem;     length++; }  // Remaining virtual functions that need to be defined by the inherited class  #endif 

main1.cpp

#include <iostream> #include "unorderedArrayListType.h"  using namespace std;   int main() {     unorderedArrayListType<int> intList(25);      int number;     cout<<"Line 3: Enter 8 integers: ";      for(int count = 0; count < 8; count++)     {         cin>>number;         intList.insertEnd(number);     }      cout<<"Line 8: intList: ";     intList.print();     cout<<endl; } 

Makefile:

all: main1   main1.o: main1.cpp     g++ -c -Wall main1.cpp  main1: main1.o     g++ -Wall main1.o -o main   clean:     rm -f *.o *~ main1 

The following is the compilation error:

make   g++ -c -Wall main1.cpp   In file included from main1.cpp:2:   unorderedArrayListType.h: In member function 'void   unorderedArrayListType<elemType>::insertAt(int, const elemType&)':   unorderedArrayListType.h:30: error: 'length' was not declared in this scope   unorderedArrayListType.h:31: error: 'list' was not declared in this scope   unorderedArrayListType.h:33: error: 'list' was not declared in this scope   

More functions of unorderedArrayListType listed and protected variables indicated as not declared in the scope. Wondering what could be the error.

New error:

make   g++ -Wall main1.o -o main   Undefined                       first referenced    symbol                             in file   arrayListType<int>::seqSearch(int const&) constmain1.o   ld: fatal: Symbol referencing errors. No output written to main   collect2: ld returned 1 exit status   *** Error code 1   make: Fatal error: Command failed for target `main1'   
like image 365
Romonov Avatar asked Jul 06 '11 06:07

Romonov


People also ask

Can template class inherit?

Inheriting from a template classIt is possible to inherit from a template class. All the usual rules for inheritance and polymorphism apply. If we want the new, derived class to be generic it should also be a template class; and pass its template parameter along to the base class.

What members of the parent class Cannot be inherited in the derived class?

Following are the properties which a derived class doesn't inherit from its parent class : 1) The base class's constructors and destructor. 2) The base class's friend functions. 3) Overloaded operators of the base class.

Is inheritance better than templates?

Templates provide sortability in a much nicer way, since the sortee doesn't need to know that it's being sorted. Complex inheritance typically results when you work with a forced mindset that everything must be an inheritance hierarchy, which is in fact rarely appropriate.

Do child classes inherit variables?

We know every Child class inherits variables and methods (state and behavior) from its Parent class. Imagine if Java allows variable overriding and we change the type of a variable from int to Object in the Child class.


2 Answers

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

like image 127
UncleBens Avatar answered Oct 07 '22 12:10

UncleBens


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.

like image 38
David Hammen Avatar answered Oct 07 '22 11:10

David Hammen