为何模板子类访问受保护成员需使用父类前缀?
为什么模板继承中直接访问基类成员会报错?
问题代码
template <class T> class Parent { protected: T _value; }; template <class T> class Child : public Parent<T> { public: void doStuff() { std::cout << _value << std::endl; } };
GCC 6.3编译报错
prog.cpp: In member function ‘void Child
::doStuff()’:
prog.cpp:14:33: error: ‘_value’ was not declared in this scope
void doStuff() { std::cout << _value << std::endl; }
^~~~~~
这个问题的核心是C++模板中的**依赖名称查找(Dependent Name Lookup)**规则,说白了就是编译器处理模板代码时,对“依赖于模板参数的内容”有特殊逻辑:
- 当
Child<T>继承自Parent<T>时,Parent<T>是依赖于模板参数T的基类——不同的T可能会让Parent<T>的实例化结果完全不同(比如存在Parent<int>的特化版本,成员结构可能和通用版不一样)。 - 在模板的定义阶段(编译器刚读到这段模板代码,还没具体实例化某个T的时候),编译器不会去解析依赖基类里的非限定名称(比如直接写
_value)。它会默认这个名称要么是Child<T>自己的成员,要么是全局名称,根本不会去基类里找——这就是报错的原因。
几种可行的解决方式
- 显式限定基类名称:像你做的那样用
Parent<T>::_value替代_value,相当于明确告诉编译器:“这个成员来自依赖基类Parent<T>,等实例化的时候再去查具体定义”。修改后代码:
template <class T> class Child : public Parent<T> { public: void doStuff() { std::cout << Parent<T>::_value << std::endl; } };
- 通过
this指针访问:this的类型是Child<T>*,同样依赖于T,所以this->_value会被当作依赖名称,编译器会延迟到实例化阶段去基类中查找:
template <class T> class Child : public Parent<T> { public: void doStuff() { std::cout << this->_value << std::endl; } };
- 使用
using声明引入基类成员:在Child<T>类体内添加using Parent<T>::_value;,后续直接用_value就会被解析为基类成员:
template <class T> class Child : public Parent<T> { using Parent<T>::_value; // 引入基类成员 public: void doStuff() { std::cout << _value << std::endl; } };
内容的提问来源于stack exchange,提问作者Niklas R
相关产品推荐
相关产品推荐

