web-dev-qa-db-fra.com

Modèles: Variables de membre de la classe mère Non visible dans la classe héritée

J'ai les 4 fichiers suivants:

  1. arrayListType.h: Déclarez et définissez arrayListType classe en tant que modèle
  2. unorderedArrayListType.h: Hérité de arrayListType classe et déclare et définit unorderedArrayListType comme modèle.
  3. main1.cpp: Programme de test pour tester unorderedArrayListType classe.
  4. Makefile

Je reçois une erreur de compilation disant lors de l'accès aux variables protégées de arrayListType in unorderedArrayListType par exemple: "La longueur non déclarée dans la présente étendue", "liste non déclarée dans cette portée", où la longueur et la liste sont des variables protégées dans arrayListType classe.

Voici les codes suivants:
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

oNUERDARRAYLISTTYPE.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

Voici l'erreur de compilation:

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  

Plus de fonctions de unorderedArrayListType variables répertoriées et protégées indiquées comme non déclarées dans la portée. Se demandant ce qui pourrait être l'erreur.

Nouvelle erreur:

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'  
38
Romonov

En effet, le parent modèle d'une classe de modèle n'est pas instancié au cours de la passe de compilation qui examine d'abord le modèle. Ces noms semblent être non dépendants de l'instanciation de gabarits particulière et, par conséquent, les définitions doivent être disponibles. (Si vous ne regardez jamais la définition de arrayListType, puis lisez le code de unorderedArrayListType _ Cela apparaîtrait le list et length doit être une sorte de Globals.)

Vous devrez dire explicitement au compilateur que les noms dépendent en fait de l'instanciation du parent.

Une façon, en utilisant this-> Avant tous les noms hérités: this->list, this->length.

Autre moyen, en utilisant des déclarations: using arrayListType<elemType>::length;c (par exemple dans la section privée de la classe dérivée).


A FAQ Entrée sur ceci: https://isocpp.org/wiki/faq/templates#nondépendant-name-lookup-members

69
UncleBens

Un commentaire étendu sur la réponse des Onclebens.

Il est toujours bon de garder à l'esprit que les modèles de classe ne sont pas des cours. Ce sont des modèles. Une façon de l'examiner: en C++, les classes ne sont pas des objets. Vous devez instancier une classe pour créer un objet. Un concept similaire s'applique aux modèles de classe et aux classes. Tout comme l'instanciation de classe crée un objet, l'instanciation de modèle de classe crée une classe.

Jusqu'à ce que le modèle soit instancié, cette relation de héritage que vous avez configurée entre unorderedArrayListType et arrayListType n'existe pas tout à fait. Le compilateur ne sait pas si vous allez définir une instanciation de modèle partielle de arrayListType qui n'a pas length et list comme membres de données. Vous devez donner au compilateur une main dans votre unorderedArrayListType en utilisant this->length et this->list ou une autre construction qui indique au compilateur que vous vous attendez à ce que ce soit des membres de données.

Supposons que vous utilisiez this->length dans unorderedArrayListType et supposons que quelqu'un vienne et écrit une instanciation de gabarits partiels de arrayListType<FooType> Cela n'a pas length et list comme membres de données. Maintenant instanciant d'un unorderedArrayListType<FooType> entraînera une erreur de compilation. Mais puisque tu ne vas pas faire ça (tu n'allais pas faire ça, es-tu?), En utilisant this->length sera OK.

13
David Hammen

J'essaierais deux choses:

1. Utilisez this-> (qui est généralement une bonne idée de faire avec des modèles).

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 le parent et utilisez-le lors de l'accès aux membres des parents :

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++;
}
6
selalerer