在C++中如果父类是模板类,在子类中直接调用 父类带模板定义的成员 的话,会报错找不到该变量,其根本原因是因为模板的二次编译机制导致的。
父类声明:
template <typename T>
class SeqList:public List<T>{
protected:
T* m_array; //顺序存储空间位置
int m_length; //当前线性表长度
public:
bool insert(int i, const T& e);
bool remove(int i);
bool set(int i, const T& e);
bool get(int i, T& e)const;
int length()const;
void clear();
//数组访问方式
T& operator [](int i);
T operator [](int i)const;
//设置顺序存储空间容量
virtual int capacity()const = 0;
};
子类声明:
template<typename T, int N>
class StaticList: public SeqList<T>{
protected:
T space[N];
public:
StaticList()
{
m_array = m_space; //error,未定义 m_array 和 m_length.
m_length = 0;
}
int capacity()const
{
return N;
}
};
问题主要在于模板要编译两次。
模板定义阶段(第一阶段)
只对模板中和模板参数无关的名字进行查找(无视那些有模板参数的部分)。由于父类是模板类,所以在第一次编译的时候那些和泛型扯上关系的变量会被无视掉。
StaticList 继承自 SeqList,在第一次编译的时候编译器会忽略掉 SeqList,假装没有看到它,因此SeqList中的成员 m_array 和 m_length 就顺理成章地被忽略了。
StaticList 中没有再次定义 m_array 和 m_length,因此编译器在第一次编译的时候无法找到m_array和length直接报错了。
模板实例化阶段(第二阶段)
在第二阶段编译器主要处理带模板参数的部分,所有和模板相关的操作都在该阶段完成。
在每个成员变量之前加入了 Base:: 或者 this 指针,通过 Base:: 或者 this 指针,将成员变量拖到第二阶段进行编译。这样才能被编译。