派生类无法直接调用基类模板函数?需强制转换的原因
问题场景
我有一个非模板基类Allocator,它实现了如下模板成员函数:
template<class T> Buffer<T> allocate(size_t n) { ... }
该函数会调用类内的纯虚非模板函数:
virtual Buffer<std::byte> allocate(size_t size, size_t align) = 0;
这个非模板allocate()由派生类重写,负责按指定对齐方式分配std::byte;而模板函数是它的封装,会自动获取类型T的对齐参数并调用:
allocate(n * sizeof(T), alignof(T));
派生类只需实现字节分配函数,就能通过继承获得类型对象的分配能力。我定义了派生类Page : public Allocator,但直接调用page.allocate<int>(10)时出现错误:
- VSCode智能提示报错:
A pointer to a bound function may only be used to call the function
- g++ 12.1.0 Rev3编译报错:
expected primary-expression before '>' token
但将对象强制转换为基类指针后,((Allocator *) &page)->allocate<int>(10)却能正常运行。
原因分析
这是C++的**名称隐藏(Name Hiding)**机制导致的:当派生类Page重写了基类的非模板allocate(size_t, size_t)函数时,派生类作用域内的allocate名称会隐藏基类中所有同名的函数(包括模板版本)。
编译器处理page.allocate<int>(10)时,会优先在派生类的作用域中查找allocate,找到的是重写的非模板版本——这个函数不需要模板参数,所以<int>会被判定为语法错误,从而抛出对应的编译报错。
而通过基类指针调用时,编译器是在基类的作用域中查找allocate,此时能正确找到模板版本的allocate<T>,因此可以正常解析模板参数并执行调用。
解决方法
不需要依赖强制转换,有两种更规范的处理方式:
- 在派生类中引入基类模板函数
在Page类的定义中添加using Allocator::allocate;,将基类的模板allocate函数引入到派生类作用域,避免被隐藏。之后直接调用page.allocate<int>(10)即可正常工作。 - 通过基类限定符直接调用
调用时明确指定基类作用域,比如写成page.Allocator::allocate<int>(10),告诉编译器要调用的是基类的模板函数。
内容的提问来源于stack exchange,提问作者Paul Deva

