请考虑以下代码:
class Base
{
public:
virtual void* allocate(){ return nullptr; }
};
template <class T> class BaseTemplate : public Base
{
public:
void* allocate() override { return new T(); }
};
class IntSpecialization : public BaseTemplate<int>
{
};
Base GetSpecialization(const int&){ return IntSpecialization(); }
目标是能够使用模板实现特化,但仍然允许用户使用基类接口,例如:
int a;
auto s = GetSpecialization(a);
auto p = s.allocate();
以上代码不起作用; s.allocate()
由于显而易见的原因总是返回nullptr
。
我绝对需要GetSpecialization
函数来返回Base
非模板类,那么我该怎么做呢?
Base
类虚方法不能是纯粹的,否则它会变成抽象的,它会在GetSpecialization
的编译失败。
解决这种模式的最佳方法是什么?使用C ++ 11? 谢谢!
答案 0 :(得分:4)
Base GetSpecialization(const int&){ return IntSpecialization(); }
您是slicing上面的IntSpecialization
对象。为了使您的代码有效,GetSpecialization
必须返回Base *
或Base&
。例如,以下内容可按您的意图使用:
std::unique_ptr<Base> GetSpecialization(const int&)
{
return std::unique_ptr<Base>(new IntSpecialization());
}
要使上述代码生效,您需要向virtual
添加Base
析构函数。
class Base
{
public:
virtual void* allocate(){ return nullptr; }
virtual ~Base() = default;
};
否则,当unique_ptr
超出范围时,它将调用delete ptr;
,其中ptr
的类型为Base *
,并且派生类对象的多态删除通过基类指针是未定义的行为,除非基类析构函数是virtual
。
答案 1 :(得分:0)
只需让Base有指向BaseTemplate的指针:
class BaseInterface {
public:
virtual void* allocate() = 0;
}
class Base
{
std::unique_ptr<BaseInterface> interface;
public:
Base( BaseInterface *i ) : interface( i ) {}
void* allocate(){ return interface->allocate(); }
};
template <class T> class BaseTemplate : public BaseInterface
{
public:
void* allocate() override { return new T(); }
};
class IntSpecialization : public BaseTemplate<int>
{
};
Base GetSpecialization(const int&){ return Base( new IntSpecialization ); }
不太详细的解决方案是使用std::function
和lambda
class Base
{
public:
typedef std::function<void *()> creator;
Base( const creator &c ) : cr( c ) {}
void *allocate() { return cr(); }
private:
creator cr;
};
template<class T>
Base GetSpecialization( const T & ) { return Base( []() { return new T; } ); }