模板:父类成员变量在继承类中不可见

49

我有以下四个文件:

  1. arrayListType.h: 以模板方式声明和定义 arrayListType 类。
  2. unorderedArrayListType.h: 继承自 arrayListType 类,并以模板方式声明和定义 unorderedArrayListType 类。
  3. main1.cpp: 测试程序,用于测试 unorderedArrayListType 类。
  4. Makefile

当在 unorderedArrayListType 类中访问 arrayListType 的受保护变量时,出现编译错误,例如:"length not declared in this scope"、"list not declared in this scope",其中 length 和 list 是 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

无序数组列表类型.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

主函数1.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个回答

91
这是因为模板类的模板父类在首次检查模板时不会被实例化。这些名称似乎与特定的模板实例化无关,因此需要可用的定义。(如果您从未查看过arrayListType的定义,则读取unorderedArrayListType的代码时,listlength似乎需要成为某种全局变量。)
您需要明确告诉编译器这些名称实际上依赖于父类的实例化。
一种方法是在所有继承的名称之前使用this->this->listthis->length
另一种方法是使用声明:using arrayListType<elemType>::length;等(例如在派生类的私有部分)。
这是一个关于此问题的常见问题解答:https://isocpp.org/wiki/faq/templates#nondependent-name-lookup-members

谢谢!我使用了“using arrayListType<elemType>::length”,解决了与变量未在范围内声明有关的错误。我只有一个更多的错误,我在问题的末尾发布了它。你能否请评论一下。谢谢! - Romonov
2
@user640639:最后一个错误信息看起来有点混乱,但它告诉你的是你没有定义一个已经声明的成员函数。虚拟成员函数必须被定义,无论它们是否在你的代码中使用,而你没有提供那个特定函数的实现。 - David Rodríguez - dribeas
@Rodriguez 谢谢!你是对的。我的seqSearch虚函数声明中有一个错误。我已经纠正了它,现在它可以工作了。 - Romonov

14

对UncleBens答案的进一步评论。

始终要记住,类模板不是类,它们是模板。一种看待方法:在C++中,类不是对象,你需要实例化一个类来创建对象。类模板和类也适用类似的概念。就像类实例化创建对象一样,类模板实例化创建类。

在模板被实例化之前,你在unorderedArrayListTypearrayListType之间设置的继承关系并不存在。编译器不知道你是否将定义一个arrayListType的部分模板实例化,其中没有lengthlist作为数据成员。你需要在unorderedArrayListType中使用this->lengththis->list或其他某些构造形式,告诉编译器你确实期望这些成员是数据成员。

假设你在unorderedArrayListType中使用了this->length,并且假设有人写了一个arrayListType<FooType>的部分模板实例化,其中没有lengthlist作为数据成员。现在实例化一个unorderedArrayListType<FooType>将导致编译时错误。但是,由于你不会这样做(你不会这样做,对吗?),使用this->length就没问题。


1
你会如何编写一个“arrayListType<FooType>的部分模板实例化,它没有长度和列表作为数据成员”?你能在回答中添加一个示例吗?谢谢。 - Isaac Turner

8

我建议尝试两件事情:

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. 对父类进行typedef,并在访问父类成员时使用:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接