使用模板访问C ++中受保护的超类成员

时间:2010-10-24 20:26:24

标签: c++ templates inheritance

为什么C ++编译器不能识别g()bSuperclass的继承成员,如下面的代码所示:

template<typename T> struct Superclass {
 protected:
  int b;
  void g() {}
};

template<typename T> struct Subclass : public Superclass<T> {
  void f() {
    g(); // compiler error: uncategorized
    b = 3; // compiler error: unrecognized
  }
};

如果我简化Subclass并且只是从Subclass<int>继承,那么它就会编译。当完全限定g()Superclass<T>::g()Superclass<T>::b时,它也会编译。我正在使用LLVM GCC 4.2。

注意:如果我在超类中公开g()b,它仍然会失败并出现相同的错误。

2 个答案:

答案 0 :(得分:47)

可以使用using

将名称拉入当前范围来修改此问题
template<typename T> struct Subclass : public Superclass<T> {
  using Superclass<T>::b;
  using Superclass<T>::g;

  void f() {
    g();
    b = 3;
  }
};

或者通过this指针访问来限定名称:

template<typename T> struct Subclass : public Superclass<T> {
  void f() {
    this->g();
    this->b = 3;
  }
};

或者,正如您已经注意到的那样,通过限定全名。

这是必要的原因是C ++不考虑超类模板进行名称​​解析(因为它们是依赖名称,并且不考虑依赖名称)。它在您使用Superclass<int>时有效,因为它不是模板(它是模板的实例化),因此其嵌套名称不是依赖名称。

答案 1 :(得分:14)

Konrad的回答并没有要求或回答所有这些中的最终“为什么”。这不仅仅是C ++委员会随意说“嘿,放弃依赖的名字,无论如何都没有人喜欢它们”。相反,编译器甚至在它们被实例化之前就对模板进行了一些检查,并且在它知道T之前它不能理解g()或b,因为它不能 - 通常 - 在可能的特化之间进行选择。基类(例如SuperClass<X>可能有int bSuperClass<Y>void b()SuperClass<Z>根本没有b。更明确的形式只是说“相信我 - 这必须来自实例化时的基类(否则会有编译器错误)”。