无法实例化抽象类:为什么模板参数(引用)导致这种情况

Cannot instantiate abstract class: Why is the template parameter (reference) causing this?

本文关键字:引用 情况 参数 抽象类 实例化 为什么      更新时间:2023-10-16

我在使用某些代码时遇到问题。

"bar":无法实例化抽象类

我(终于)能够在少量代码中重新创建错误。

struct SomeStruct
{
    // ******
};
template <typename TIN, typename TOUT, typename TINDEX>
struct IFoo
{
public:
    virtual void add(const TIN item) = 0; // <-- BAD
    //virtual void add(const TOUT& item) = 0; // <-- GOOD
    // ******
};
template <typename TVALUE, typename TINDEX>
struct Bar : IFoo<TVALUE &, TVALUE, TINDEX>
{
public:
    void add(const TVALUE& item)
    {
        // ******
    }
    // ******
};
int main(int argc, char *argv[])
{
    SomeStruct someStruct;
    Bar<SomeStruct, int> bar = Bar<SomeStruct, int>();
    bar.add(someStruct);
    // ******
}

任何人都可以告知为什么使用带有模板参数的引用会导致这种情况吗?

这里的问题是,当您编写const TIN并且TIN是引用类型时,const应用于引用而不是值类型。

这就是为什么你看到const TINconst TOUT&不同的行为,即使你认为它们应该是相同的。

一个简单的解决方法是将const添加到IFoo实例化中的值类型:

struct Bar : IFoo<const TVALUE &, TVALUE, TINDEX>
//          here  ^^^^

您的问题可以追溯到函数签名等基本概念:函数签名/原型由函数名称、参数数量、参数数据类型和这些参数的出现顺序给出。

对于任何两个函数,

如果上述任何一项不同,那么您正在处理两个不同的函数。

更确切地说,这两个代表两个不同的签名:

virtual void add(const TIN item) = 0; 
virtual void add(const TOUT& item) = 0;

由于您只实现了派生类中的第二个,因此会出现错误。

我们可以进一步简化您的示例:

template <typename T>
struct IFoo {
    virtual void add(const T item) = 0;
};
template <typename T>
struct Bar : IFoo<T&> {
    void add(const T& item) { }
};

Bar中,您将item作为const T的参考。在 IFoo 中,您声明了一个纯虚方法,该方法对T进行const引用。但是所有的引用本质上都是const的,所以这是多余的 - 它相当于只引用T

对于Bar<int> - IFoo::add()的签名是void add(int& ),而Bar::add()void add(const int& )。这些签名不匹配 - 因此Bar仍然是一个抽象类。只是一个隐藏IFoo::add().

如果您有 C++11 编译器,则最好将 override 关键字添加到Bar::add(),以便收到以下编译器错误:

main.cpp:15:10: error: 'void Bar<T>::add(const T&) [with T = int]' marked 'override', but does not override
     void add(const T& ) override { }
          ^