访问超类的保护成员在C++中使用模板
为什么不能将C++编译器识别g()
和b
被继承的Superclass
成员在此代码所示:访问超类的保护成员在C++中使用模板
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
和刚刚继承然后它编译。当完全符合g()
时,它也编译为Superclass<T>::g()
和Superclass<T>::b
。我正在使用LLVM GCC 4.2。
注意:如果我在超类中公开g()
和b
,它仍会失败并出现相同的错误。或者
template<typename T> struct Subclass : public Superclass<T> {
void f() {
this->g();
this->b = 3;
}
};
,正如你:
这可以通过使用using
拉的名字到当前范围修改为:
template<typename T> struct Subclass : public Superclass<T> {
using Superclass<T>::b;
using Superclass<T>::g;
void f() {
g();
b = 3;
}
};
或通过该0指针访问限定名称已经注意到,通过限定全名。
这是必要的原因是,C++不考虑名称解析的超类模板(因为它们是从属名称和从属名称不予考虑)。它在您使用Superclass<int>
时起作用,因为它不是模板(它是实例化模板),因此它的嵌套名称不是,而是依赖于的名称。
Konrad的回答并没有要求或回答最终的“为什么”。这不仅仅是C++委员会任意说“嘿,放弃依赖名字,反正没有人喜欢它们”。相反,编译器甚至在实例化之前对模板进行了一些检查,并且直到它知道T之前,它才具有g()或b的意义,因为它通常不能 - 通常 - 在可能的特化之间进行选择基类(例如SuperClass<X>
可能有int b
,而SuperClass<Y>
有void b()
和SuperClass<Z>
根本没有b
)。更明确的形式只是说“相信我 - 在实例化时它必须来自基类”(否则会出现编译器错误)“。
有点有道理,但它绝对是模板的一个比较模糊的“特征”。 – ChrisWue 2014-01-08 22:06:22
@ChrisWue:这场比赛有很多比赛! ;-) – 2014-01-09 02:47:23
GCC能够在过去的20世纪90年代处理这个问题,但随着C++的发展,它发生了变化。我认为在某些情况下处理它的方式会造成问题,这就是为什么它发生了变化。 – PolarBear2015 2017-02-06 14:32:28
微软的编译器不服从这条规则。我很生气 – 2010-10-24 21:06:24
谢谢,那有效。 – andrewz 2010-10-25 00:44:11
@阿门:只有这一个规则?哇,它真的*变得更好了。 :-D – 2010-10-25 06:04:18