C++ 无法实例化抽象类:为什么模板参数(引用)会导致这种情况?
我在一些代码方面遇到了问题 “Bar”:无法实例化抽象类 我终于能够用少量代码重新创建错误C++ 无法实例化抽象类:为什么模板参数(引用)会导致这种情况?,c++,templates,abstract,C++,Templates,Abstract,我在一些代码方面遇到了问题 “Bar”:无法实例化抽象类 我终于能够用少量代码重新创建错误 struct SomeStruct { // ****** }; template <typename TIN, typename TOUT, typename TINDEX> struct IFoo { public: virtual void add(const TIN item) = 0; // <-- BAD //virtual void add(con
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);
// ******
}
有人能告诉我们为什么使用模板参数引用会导致这种情况吗?您的问题可以追溯到函数签名等基本概念:函数签名/原型由函数名称、参数数量、参数数据类型以及这些参数的出现顺序给出 对于任何两个函数,如果上述任何一个函数不同,则表示您正在处理两个不同的函数 更确切地说,这两个代表两个不同的签名:
virtual void add(const TIN item) = 0;
virtual void add(const TOUT& item) = 0;
由于您只在派生类中实现了第二个,因此会出现错误。您的问题可以追溯到函数签名等基本概念:函数签名/原型由函数名、参数数量、参数的数据类型以及这些参数的出现顺序给出 对于任何两个函数,如果上述任何一个函数不同,则表示您正在处理两个不同的函数 更确切地说,这两个代表两个不同的签名:
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) { }
};
我们可以将您的示例进一步简化为:
template <typename T>
struct IFoo {
virtual void add(const T item) = 0;
};
template <typename T>
struct Bar : IFoo<T&> {
void add(const T& item) { }
};
这里的问题是,当您编写const TIN并且TIN是引用类型时,const应用于引用而不是值类型 这就是为什么你会看到const TIN和const TOUT的不同行为&即使你认为他们应该是一样的 解决此问题的一个简单方法是在IFoo实例化中将const添加到值类型中:
struct Bar : IFoo<const TVALUE &, TVALUE, TINDEX>
// here ^^^^
这里的问题是,当您编写const TIN并且TIN是引用类型时,const应用于引用而不是值类型 这就是为什么你会看到const TIN和const TOUT的不同行为&即使你认为他们应该是一样的 解决此问题的一个简单方法是在IFoo实例化中将const添加到值类型中:
struct Bar : IFoo<const TVALUE &, TVALUE, TINDEX>
// here ^^^^
因为您是在Bar addconst TVALUE&中实现的,带有引用。这是一个不同于在基类中声明为纯虚拟的函数的函数。通过修改Bar中的定义来撤销addconst TVALUE&item override,您将看到@Hcorg所说的是正确的;编译器会告诉您,您没有重写基类中的函数。这不是问题所在,因为TIN是&。因为您是在带引用的Bar addconst TVALUE&中实现的。这是一个不同于在基类中声明为纯虚拟的函数的函数。通过修改Bar中的定义来撤销addconst TVALUE&item override,您将看到@Hcorg所说的是正确的;编译器会告诉您,您没有重写基类中的函数。这不是问题所在,因为TIN是TOUT&@bikie:If TIN==TOUT&,const TIN仍然不同于const TOUT&。在这种情况下,const-TIN仍然只是TOUT&,这与const-TOUT&不同。第一个函数接受TIN类型的变量作为参数,第二个函数接受对变量的引用。因此,即使是TIN和TOUT都是相同的数据类型,引用类型和变量也不相同thing@Beakie:如果TIN==TOUT&,则const TIN仍然不同于const TOUT&。在这种情况下,const-TIN仍然只是TOUT&,这与const-TOUT&不同。第一个函数接受TIN类型的变量作为参数,第二个函数接受对变量的引用。所以即使是TIN和TOUT都是相同的数据类型,引用类型和变量也不是一回事