任何人都可以解释为什么下面的代码会给出错误"错误C2259:' PropertyValue':无法实例化抽象类"在Visual Studio 2015 C ++中?
编译器是否无法识别派生类ConvertToDevice()
中的条件指定函数PropertyValue
是否具有相同的签名?
非常感谢,
约翰
#include <type_traits>
#include <typeinfo>
class BasePropertyValue
{
public:
virtual int ConvertToDevice(void** ptrdObject) = 0;
};
template<typename T> class PropertyValue : public BasePropertyValue
{
public:
T value;
PropertyValue(T val)
{
value = val;
}
template<class Q = T>
typename std::enable_if<!std::is_pointer<Q>::value, int>::type ConvertToDevice(void** ptrdObject)
{
return 1;
}
template<class Q = T>
typename std::enable_if<std::is_pointer<Q>::value, int>::type ConvertToDevice(void** ptrdObject)
{
return 2;
}
};
void main()
{
PropertyValue<double>* prop1 = new PropertyValue<double>(20);
prop1->ConvertToDevice(nullptr);
double x = 20;
PropertyValue<double*>* prop2 = new PropertyValue<double*>(&x);
prop2->ConvertToDevice(nullptr);
return;
}
[edit]由于条件特征方面,这不是一个重复的问题。
答案 0 :(得分:2)
首先,您声明要尝试覆盖的函数作为模板。你不能拥有模板虚拟功能。就这么简单。
对于解决方案,您似乎只是为了能够在两个实现之间切换而使这些模板。一个简单的解决方案是实现一个覆盖的单个函数,然后在其中调用模板函数:
template<typename T>
struct PropertyValue : BasePropertyValue {
T value;
// simpler constructor
PropertyValue(T val) : value{std::move(val)} {}
// the override keyword is important
int ConvertToDevice(void** ptrdObject) override
{
return ConvertToDeviceImpl(ptrdobject);
}
private:
template<class Q = T>
typename std::enable_if<!std::is_pointer<Q>::value, int>::type
ConvertToDeviceImpl(void** ptrdObject)
{
return 1;
}
template<class Q = T>
typename std::enable_if<std::is_pointer<Q>::value, int>::type
ConvertToDeviceImpl(void** ptrdObject)
{
return 2;
}
};
答案 1 :(得分:1)
问题在于
template<class Q = T>
typename std::enable_if<!std::is_pointer<Q>::value, int>::type ConvertToDevice(void** ptrdObject)
{
return 1;
}
是模板方法,它与基类中的纯虚方法不匹配(并且不会覆盖)。
与其他启用SFINAE的功能相同。
所以PropertyValue
仍然是纯虚拟类,无法实例化。
可能的解决方案是创建一个中间基类,如下面的midClass
class BasePropertyValue
{ public: virtual int ConvertToDevice (void ** ptrdObject) = 0; };
template <typename T, bool = std::is_pointer<T>::value>
class midClass;
template <typename T>
class midClass<T, false> : public BasePropertyValue
{ public: int ConvertToDevice (void ** ptrdObject) override { return 1; } };
template <typename T>
class midClass<T, true> : public BasePropertyValue
{ public: int ConvertToDevice (void ** ptrdObject) override { return 2; } };
template <typename T>
class PropertyValue : public midClass<T>
{
public:
T value;
PropertyValue (T val)
{ value = val; }
};