C++继承实例化模板类编译失败:无法识别成员字段的原因与解决
C++继承模板基类后构造函数初始化列表无法访问成员的问题及解决
问题代码
struct My { int id; int value; }; template < class T > class IsElement : public T { protected: IsElement<T>* the_next; }; struct elem : public IsElement<My> { elem(int i, int v) : id(i), value(v), the_next(nullptr) { } }; int main() { return 0; }
编译错误信息
<source>: In constructor 'elem::elem(int, int)': <source>:13:26: error: class 'elem' does not have any field named 'id' elem(int i, int v) : id(i), value(v), the_next(nullptr) { ^~ <source>:13:33: error: class 'elem' does not have any field named 'value' elem(int i, int v) : id(i), value(v), the_next(nullptr) { ^~~~~ <source>:13:43: error: class 'elem' does not have any field named 'the_next' elem(int i, int v) : id(i), value(v), the_next(nullptr) { ^~~~~~~~ Execution build compiler returned: 1
疑问
我认为所有成员都应可访问,为何编译器无法找到这些成员字段?该如何修复?
原因分析
这是C++模板依赖名称查找规则导致的:
IsElement<My>是依赖模板参数的基类,编译器处理elem定义时,不会自动将基类成员纳入子类作用域。- 即便基类已经用具体类型
My实例化,初始化列表里的成员名称也不会被自动解析到基类中,必须显式指明作用域。 - 另外
the_next是基类的protected成员,子类虽有权访问,但同样需要明确作用域才能在初始化列表里引用。
修复方案
方案一:显式指定基类作用域
在初始化列表中通过基类名称限定成员:
struct elem : public IsElement<My> { elem(int i, int v) : IsElement<My>::id(i), IsElement<My>::value(v), IsElement<My>::the_next(nullptr) { } };
方案二:用using引入基类成员
在子类中声明引入基类成员,让这些成员进入子类作用域,之后可直接在初始化列表使用:
struct elem : public IsElement<My> { using IsElement<My>::id; using IsElement<My>::value; using IsElement<My>::the_next; elem(int i, int v) : id(i), value(v), the_next(nullptr) { } };
补充说明
两种方案均兼容C++11及以上标准。方案一适合单次引用场景,直接明了;方案二更适合多次使用基类成员的情况,代码更简洁。
内容的提问来源于stack exchange,提问作者gongliming7
相关产品推荐
相关产品推荐

