【问题标题】:Accessing base member functions in class derived from template class [duplicate]访问从模板类派生的类中的基成员函数[重复]
【发布时间】:2014-08-01 05:34:34
【问题描述】:

我正在开发一个库,我设计了一个复杂的继承,其中包括模板类并从它们派生。 我的问题是一个基模板类具有虚拟重载运算符,它接受 2 个参数并返回一些值。在基类中实现了这个操作符,大多数派生类没有重新实现这个操作符。

其他一些类使用派生类来完成某些工作并利用它们的操作员成员函数。只要派生类没有其他重载运算符,即使参数数量不同,一切都可以正常工作。如果是这样,则无法将基类运算符用作object(),因为编译器找不到正确的成员函数(抱怨参数计数不匹配)。

是否指定了基类的默认模板参数并不重要。派生类的定义顺序也不会改变导致问题的运算符(它始终是SpecificDerived 类)。

下面我提出简化的问题。

[EDIT] 示例已简化

基类定义:

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。

【问题讨论】:

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


    【解决方案1】:

    当类模板派生自基类模板时,基类成员在派生类模板定义中不可见。 (这是有道理的;在您专门化之前,没有类,因此也没有成员。显式专门化总是可以改变任何给定模板类的含义。)

    换句话说,基本模板成员名称是依赖名称,不会在模板定义查找的第一阶段进行查找。

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

    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();
      

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


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

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

    【讨论】:

    • 但是,在我的示例中,只要派生类或基类中没有其他重载函数,一切都可以正常工作,但从你所说的看来,即使那样它也不应该工作。
    • @KrzysztofPilch:你能做一个的例子来说明这种情况吗?
    • 我已将示例编辑为更简单。
    • @KrzysztofPilch:现在你的问题完全不同。但无论如何,我已经相应地编辑了答案。顺便说一句,你和我对small例子的理解是不同的。如果您愿意,我可以向您展示如何在一个小示例中演示完全相同的问题。
    • 我想看一个小例子。它可能很有用。
    猜你喜欢
    • 1970-01-01
    • 2018-09-18
    • 2012-09-12
    相关资源
    最近更新 更多