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

时间:2014-06-11 08:33:38

标签: c++ templates inheritance name-lookup template-inheritance

我正在我的工作中开发一个库,我设计了一个复杂的继承,包括模板类并从中派生出来。 我的问题是基本模板类有虚拟重载运算符,它接受2个参数并返回一些值。在基类中,实现了此运算符,并且大多数派生类都不会重新实现此运算符。

其他一些类使用派生类进行某些工作并使用其运算符成员函数。只要派生类没有其他重载运算符,即使使用不同数量的参数,一切都可以正常工作。如果有的话,那么基类操作符不能用它作为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;
}

编译器退出时出现错误,声称no matching function for call to 'SpecificDerived2::memberFunc(float)'功能存在gobble。只有当派生类或基类具有两个具有相同名称但不同参数的重载函数时,问题才存在。

我正在使用支持c ++ 11的MinGW32 4.8.1。

1 个答案:

答案 0 :(得分:8)

当类模板派生自基类模板时,基类成员在派生类模板定义中不可见。 (这是有道理的;直到你专门化,没有类,所以没有成员。明确的专业化总是可以改变任何给定模板类的含义。)

换句话说,基本模板成员名称是从属名称,在模板定义查找的第一阶段没有查找。

有三种方法可以解决这个问题。让我们通过一个简单的例子来具体化:

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. 限定名称:

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

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

    (这不适用于类型名称。)

  3. 使用using声明:

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

    (这不适用于模板名称。)


  4. 更新:编辑后,问题完全不同。模板根本不起作用,因为问题不包含模板,只包含类。发生的事情很简单,即派生类中的成员函数隐藏基类中同名的成员函数,因此SpecificDerived2::memberFunc的存在隐藏了基本成员函数。简单的解决方案是使用using声明取消隐藏同名的基本成员:

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