继承类模板时要通过this指针或基类名调用基类成员

 

在C++中,继承类模板时,调用基类的成员时,需要通过this指针或者基类名来调用。否则会出现编译错误。

问题代码1

template <typename T>
class base {

protected:
    int x;
};

template <typename T>
class derived : public base<T> {

public:
    int f() { return x; } // error: use of undeclared identifier 'x'
};

int main() {
    derived<int> d;
    d.f();
    return 0;
}

原因分析2.3

两阶段编译

  1. 第一阶段:当编译器看到模板时,它也会立即执行某些检查,但所有和模板参数相关的检查都会被推迟到实例化模板的时候。此时父类是模板类,在这一阶段会被忽略。
  2. 第二阶段:在实例化模板的时候,才会对模板参数进行查找。

结合本例:

  1. 父类base是模板类,所以在第一阶段编译时,编译器会忽略父类的成员。
  2. 但是第一阶段编译时,编译器无法找到x,所以会报错。

解决方法

通过this指针调用基类成员。将其推迟到第二阶段编译时,这时候编译器已经知道base的成员。

具体的代码就是将return x;改为return this->x;

template <typename T>
class base {

protected:
    int x;
};

template <typename T>
class derived : public base<T> {

public:
    int f() { return this->x; } // error: use of undeclared identifier 'x'
};

int main() {
    derived<int> d;
    d.f();
    return 0;
}

以一个伪代码来分析代码会在哪个阶段报错4

template <class T>
T add(T a, T b)
{
    undefine(); //未定义,与模板参数无关,第一阶段报错

    undefine(a, b); //未定义,与模板参数有关,二阶段报错

    static_assert(sizeof(int) > 100, "Error!"); //与模板参数无关,一阶段报错

    static_assert(sizeof(T) > 100, "Error!");//与模板参数有关,二阶段报错

    return a + b;
}

参考资料

  1. why-do-i-have-to-access-template-base-class-members-through-the-this-pointer
  2. C++继承模板类,需要使用this指针或者Base::调用成员变量
  3. c++模板类的两阶段查找
  4. c++模板编程-两阶段编译检查