шаблоны: переменные-члены родительского класса не видны в унаследованном классе - PullRequest
36 голосов
/ 06 июля 2011

У меня есть следующие 4 файла:

  1. arrayListType.h: объявить и определить arrayListType класс как шаблон
  2. unorderedArrayListType.h: Унаследовано от arrayListType class иОбъявляет и определяет unorderedArrayListType как шаблон.
  3. main1.cpp: тестовая программа для проверки unorderedArrayListType класса.
  4. Makefile

Я получаю сообщение об ошибке компиляции, когда при доступе к защищенным переменным arrayListType в unorderedArrayListType например: "длина не объявлена ​​в этой области", "«Список не объявлен в этой области», где длина и список являются защищенными переменными в arrayListType классе.

Ниже приведены коды:
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

Ниже приведена ошибка компиляции:

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  

Дополнительные функции из unorderedArrayListType перечислены и защищенные переменные указаны как не объявленные в области.Интересно, в чем может быть ошибка.

Новая ошибка:

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'  

Ответы [ 3 ]

64 голосов
/ 06 июля 2011

Это связано с тем, что родительский элемент шаблона класса не создается во время этапа компиляции, который сначала проверяет шаблон.Эти имена, по-видимому, не зависят от конкретного экземпляра шаблона, и поэтому определения должны быть доступны.(Если вы никогда не посмотрите на определение arrayListType, то, читая код unorderedArrayListType, вы увидите, что list и length должны быть своего рода глобалами.)

Вы будетенужно явно указать компилятору, что имена на самом деле зависят от создания родительского объекта.

В одну сторону, используя this-> перед всеми унаследованными именами: this->list, this->length.

Другой способ, используя объявления: using arrayListType<elemType>::length; и т. Д. (Например, в закрытом разделе производного класса).


Запись FAQ по этому вопросу: https://isocpp.org/wiki/faq/templates#nondependent-name-lookup-members

12 голосов
/ 06 июля 2011

Расширенный комментарий к ответу UncleBens.

Всегда полезно помнить, что шаблоны классов не являются классами.Это шаблоны.Один из способов взглянуть на это: в C ++ классы не являются объектами.Вам нужно создать экземпляр класса для создания объекта.Аналогичная концепция применяется к шаблонам классов и классам.Подобно тому, как создание экземпляра класса создает объект, создание экземпляра шаблона класса создает класс.

До создания экземпляра шаблона отношения наследования, которые вы установили между unorderedArrayListType и arrayListType, не совсем существуют.Компилятор не знает, собираетесь ли вы определить частичное создание экземпляра шаблона arrayListType, в котором нет length и list в качестве элементов данных.Вам необходимо помочь компилятору в unorderedArrayListType, используя this->length и this->list или какую-либо другую конструкцию, которая сообщает компилятору, что вы ожидаете, что они будут членами данных.

Предположим, вы используете this->length в unorderedArrayListType, и предположим, что кто-то приходит и пишет частичную реализацию шаблона arrayListType<FooType>, в которой нет length и list в качестве элементов данных.Теперь создание экземпляра unorderedArrayListType<FooType> приведет к ошибке времени компиляции.Но так как вы не собираетесь этого делать (вы не собираетесь этого делать, не так ли?), Использование this->length будет в порядке.

6 голосов
/ 06 июля 2011

Я бы попробовал две вещи:

1.Используйте this-> (что обычно хорошо подходит для шаблонов).

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.Введите определение родителя и используйте его при доступе к родительским элементам:

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++;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...