无法从继承的 class 模板中找到重载方法

can't find overloaded method from inherited class template

这是我第一次使用 class 模板,所以如果我犯了一个简单的错误,请不要太苛刻。

我有一个 class 模板 class A<class T>。它有一个纯虚拟的方法 init(),因此将在每个派生的 class 中单独实现。所有这些可能派生的 classes 的共同点是一个 init(T* i_x),它基本上做一些一般的事情然后调用 init()。因为这对于每个派生的 class 都是相同的,所以我想在基础 class 模板中定义它。但不知何故,我的编译器找不到正确的函数。

如果我尝试在派生的对象上使用 init(T* i_x) class A_der 我得到错误:

no matching function for call to 'A_der::init(B_der*)

用于模板参数 T 的 classes 将全部派生自另一个 class B。因此,错误消息涉及从 class B.

派生的 class B_der

我把问题归结为一个小例子,它应该包含对问题重要的所有内容。如果我尝试在 Visual Studio 中编译此示例(通常我在 STM32CubeIDE 中工作),我会收到以下错误

Severity Code Description Project File Line Suppression State Error C2660 'A_der::init': function does not take 1 arguments template_class-overload_inherited_method [...]\main.cpp 8

所以编译器此时找到的唯一函数是 init() 而不是基础 class 模板方法 init(T* ).

有人能告诉我为什么会这样吗?我该怎么做才能得到我想要的行为(无需在 A 的每个派生 class 中实现类似的 init(T* )

这是我的示例代码:

base class 模板 A - 声明 - A.hpp

template<class T>
class A
{
protected:
    T* m_x;

public:
    virtual void connect(T* i_x) final;

    virtual void init() = 0;

    virtual void init(T* i_x) final;
};

base class 模板 A - 实施 - A.cpp

#include "A.hpp"

template<class T>
void A<T>::connect(T* i_x)
{
    //some checks
    m_x = i_x; //connects object of B to A
}

template<class T>
void A<T>::init(T* i_x)
{
    connect(i_x);
    init();
}

派生classA_der

#include "A.hpp"
#include "B_der.hpp"

#pragma once
class A_der : public A<B_der>
{
    void init() override;
};

void A_der::init()
{
    //Initialization which needs a B_der connected already
}

main.cpp

#include "B_der.hpp"
#include "A_der.hpp"

int main(void)
{
    B_der testB;
    A_der testA;
    testA.init(&testB);

    return 0;
}

为了完整起见:

class B
{

};

class B_der : public B
{

};

编辑 - 已解决

非常感谢您的快速回复。 @BoP 和@Jarod42 的评论组合解决了这个问题。 我不得不用 using A<B_der>::init 取消隐藏方法(实际上重命名可能是更优雅的方式)并将 A 的实现移动到 A.hpp.

我将在这里为我提供使用 Visual Studio 2019 成功构建的更新示例:

基础classA

template<class T>
class A
{
protected:
    T* m_x;

public:
    virtual void connect(T* i_x) final;

    virtual void init() = 0;

    virtual void init(T* i_x) final;
};


template<class T>
void A<T>::connect(T* i_x)
{
    //some checks
    m_x = i_x; //connects object of B to A
}

template<class T>
void A<T>::init(T* i_x)
{
    connect(i_x);
    init();
}

推导classA_der

A_der.hpp

#include "A.hpp"
#include "B_der.hpp"

class A_der : public A<B_der>
{
public:
    void init() override;

    using A<B_der>::init;
};

A_der.cpp

#include "A_der.hpp"

void A_der::init()
{
    //Initialization which needs a B_der connected already
}

main.cpp

#include "B_der.hpp"
#include "A_der.hpp"

int main(void)
{
    B_der testB;
    A_der testA;
    testA.init(&testB);

    return 0;
}

完整性

B.hpp

class B
{
};

B_der.hpp

#include "B.hpp"

class B_der : public B
{
};

前面的例子中A_derpublic的方法我也忘记了,这里更正一下。我在这个例子中删除了 #pragma onces。

class A_der : public A<B_der>
{
    void init() override;
};

当您在派生 class 中声明一个函数 init 时,它会隐藏基 class 中所有名为 init 的东西。这就像在内部作用域中声明某些东西一样——它从外部作用域中隐藏同名的东西。

有多种方法可以导入隐藏名称,但一个简单的解决方案是选择一个不同的名称,例如 init_base。或者,可能更好,将参数传递给 class 构造函数。