I have the following 4 files:
arrayListType.h
: Declare and define arrayListType
class as a template unorderedArrayListType.h
: Inherited from arrayListType
class and Declares and defines unorderedArrayListType
as a template. main1.cpp
: Test program to test unorderedArrayListType
class. 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'
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.
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.
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.
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.
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With