从模板类派生的类中访问基础成员函数

3
我正在开发一份工作文库,其中包括模板类和从中派生出的复杂继承关系。 我的问题在于,一个基础模板类拥有虚拟重载运算符,它带有两个参数并返回某个值。在基类中实现了这个运算符,在大多数派生类中都没有重新实现该运算符。
一些其他类使用派生类进行一些工作,并利用它们的运算符成员函数。只要派生类没有其他重载的运算符(即使参数个数不同),所有的事情都很顺利。但是如果有一个派生类有其他重载的运算符,则无法像object()那样访问基类运算符,因为编译器找不到适当的成员函数(抱怨参数数量不匹配)。
无论是否指定了基类的默认模板参数,都没有关系。此外,定义派生类的顺序也不会改变造成问题的运算符(它始终是SpecificDerived类)。
下面我给出简化后的问题。
[编辑]示例已经简化
基类定义:
template<class ret_t>
class TemplateBase2
{
public:
    virtual ~TemplateBase2()
    {
    }

    virtual ret_t memberFunc(ret_t x)
    {
        return x * 2;
    }
};

派生类的用户定义:

template <class worker, class ret_t>
ret_t gobble(worker w, float f)
{
    return w.memberFunc((ret_t)f);
}

派生类:

class SpecificDerived2: public TemplateBase2<float>
{
public:
    float memberFunc()
    {
        return 3.14;
    }
};

主要功能:

#include <iostream>
#include "TemplateBase2.h"

using namespace std;

int main()
{
    SpecificDerived2 sd2;

    cout << "sd2: " << gobble<SpecificDerived2, float>(sd2, 3.14f) << endl; 
    return 0;
}

编译器报错,声称从“gobble”函数中不存在与“SpecificDerived2 :: memberFunc(float)”相匹配的函数。 只有当派生类或基类具有相同名称但不同参数的两个重载函数时才存在问题。
我正在使用支持c ++ 11的MinGW32 4.8.1。
1个回答

15
当一个类模板继承自另一个类模板时,在派生类模板定义中,基类成员不可见。(这是有道理的;在进行特化之前,没有类,因此也没有成员。显式特化始终可以改变任何给定模板类的含义。)
换句话说,基本模板成员名称是依赖名称,不会在模板定义查找的第一阶段中查找。
有三种方法可以解决这个问题。让我们通过一个简单的例子来具体说明:
template <typename T> struct Foo
{
    int data;
    using type = const T &; 
    void gobble() const;
    template <int N> void befuddle();
};

template <typename T> struct X : Foo<T> { /* ... */ };

现在在派生类模板定义的上下文中,您可以...
  1. Qualify the name:

    Foo<T>::data = 10;
    typename Foo<T>::type x;
    Foo<T>::gobble();
    Foo<T>::template befuddle<10>();
    
  2. Use this:

    this->data = 10;
    this->gobble();
    this->template befuddle<10>();
    

    (This doesn't work for type names names.)

  3. Use a using declaration:

    using Foo<T>::data;
    using Foo<T>::gobble;
    using type = typename Foo<T>::type;
    
    data = 10;
    gobble();
    

    (This doesn't work for template names.)

更新:在您的编辑后,这个问题完全不同了。模板在这里根本没有起到作用,因为问题中没有模板,只有类。发生的简单事实是派生类中的成员函数隐藏了基类中相同名称的成员函数,所以存在SpecificDerived2::memberFunc就会隐藏基类成员函数。简单的解决方法是使用using声明取消隐藏相同名称的基类成员。
class SpecificDerived2 : public TemplateBase2<float>
{
public:
    using TemplateBase2<float>::memberFunc;
//  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    float memberFunc()
    {
        return 3.14;
    }
};

然而,在我的例子中,只要派生类或基类中没有其他重载函数,一切都能正常工作,但从你所说的来看,即使有重载函数也不应该起作用。 - Krzych
@KrzysztofPilch:你能否提供一个小的示例来说明这种情况吗? - Kerrek SB
我已经编辑了例子,使其更简单。 - Krzych
1
@KrzysztofPilch:现在你的问题已经完全不同了。但是我已经相应地编辑了答案。顺便说一句,你和我对于“小”示例的理解是不同的。如果你愿意,我可以向你展示如何用一个小例子演示完全相同的问题。 - Kerrek SB
我想看一个小例子。这可能会很有用。 - Krzych
在我的实际代码中,基类定义了2个虚拟重载函数,派生类仅覆盖其中一个。在这种情况下,我期望另一个基类成员函数可以在不使用using子句的情况下访问。 - Krzych

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接