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

and*_*ewz 38 c++ inheritance templates

为什么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
  }
};
Run Code Online (Sandbox Code Playgroud)

如果我简化SubclassSubclass<int>从那时继承它就会编译.它还会编译时完全限定g()Superclass<T>::g()Superclass<T>::b.我正在使用LLVM GCC 4.2.

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

Kon*_*lph 49

这可以通过使用以下方法将名称拉入当前范围来修改using:

template<typename T> struct Subclass : public Superclass<T> {
  using Superclass<T>::b;
  using Superclass<T>::g;

  void f() {
    g();
    b = 3;
  }
};
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

  • @Armen:只有这一条规则?哇,它确实*变得更好了.:-D (10认同)
  • 微软的编译器无法遵守这一规则.我很生气 (8认同)
  • 请注意,如果模板参数过多,您也可以使用`Subclass :: Superclass ::`进行限定. (2认同)

Ton*_*roy 14

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