使用部分模板特化覆盖抽象成员函数

时间:2013-04-04 18:35:58

标签: c++ templates inheritance abstract-class

我正在尝试在C ++中实现特定的模板设计,并遇到了我想要解决的问题。以下是设置,并说明要遵循的问题。

我声明了一个模板化的抽象基类,如下所示:

template <class TModel, class TVertex>
class AttributeEvaluator2f
{
public:
    virtual void evaluate( TModel& model, TVertex& v, float x, float y ) = 0;
};

然后我想实现专门化其中一个模板参数的子类,如下所示:

template <class TVertex>
class SurfacePositionFromSphere : public AttributeEvaluator2f<Sphere3f,TVertex>
{
public:
    virtual void evaluate( Sphere3f& sphere, TVertex& v, float theta, float phi )
    {
        sphere.SamplePosition( v.position, theta, phi );
    };
};
然后我会根据这些类实例化一个对象:

SurfacePositionFromSphere<BasicVertexDX11::Vertex> attribute();

编译错误表明我从未将抽象方法实现为原始基类。这可能是因为在子类中,我直接使用第一个参数声明方法已经是专用的(在这种情况下为Sphere3f)。

所以问题是,是否有可能以这种方式覆盖抽象基类方法参数的类型?如果没有,是否有类似的机制可用于提供类似的功能?

提前感谢您的帮助!

编辑:由于模板展开,确切的错误消息是巨大的,但这里是它的主要部分供您参考:     错误C2259:'Glyph3 :: AttributeEvaluator2f':无法实例化抽象&gt;类     1 GT;同     1 GT; [     1 GT;的TModel = Glyph3 :: Sphere3f,     1 GT; TVertex = Glyph3 :: BasicVertexDX11 ::顶点     1 GT; ]     1 GT;由于以下成员:     1 GT; 'void Glyph3 :: AttributeEvaluator2f :: evaluate(TModel&amp;,TVertex&amp;,float,float)':是抽象的     1 GT;同     1 GT; [     1 GT;的TModel = Glyph3 :: Sphere3f,     1 GT; TVertex = Glyph3 :: BasicVertexDX11 ::顶点     1 GT; ]     1 GT; c:\ users \ zij1fh \ documents \ visual studio 2012 \ projects \ hg3 \ trunk \ hieroglyph3 \ source \ rendering \ attributeevaluator2f.h(26):参见'Glyph3 :: AttributeEvaluator2f :: evaluate'的声明     1 GT;同     1 GT; [     1 GT;的TModel = Glyph3 :: Sphere3f,     1 GT; TVertex = Glyph3 :: BasicVertexDX11 ::顶点     1 GT; ]     1 GT; c:\ program files(x86)\ microsoft visual studio 11.0 \ _vc \ include \ xmemory0(751):参见函数模板实例化'void std :: allocator&lt; _Ty&gt; :: construct&lt; _Objty,_Ty&gt;(_ Objty *,正在编译_V0_t&amp;&amp;)     1 GT;同     1 GT; [     1 GT; _Ty = Glyph3 :: AttributeEvaluator2f,     1 GT; _Objty = Glyph3 :: AttributeEvaluator2f,     1 GT; _V0_t = Glyph3 :: AttributeEvaluator2f     1 GT; ]     1 GT; c:\ program files(x86)\ microsoft visual studio 11.0 \ _vc \ include \ xmemory0(751):参见函数模板实例化'void std :: allocator&lt; _Ty&gt; :: construct&lt; _Objty,_Ty&gt;(_ Objty *,正在编译_V0_t&amp;&amp;)     1 GT;同     1 GT; [     1 GT; _Ty = Glyph3 :: AttributeEvaluator2f,     1 GT; _Objty = Glyph3 :: AttributeEvaluator2f,     1 GT; _V0_t = Glyph3 :: AttributeEvaluator2f     1 GT; ]     1 GT; c:\ program files(x86)\ microsoft visual studio 11.0 \ _vc \ include \ xmemory0(903):参见函数模板实例化'void std :: allocator_traits&lt; _Alloc&gt; :: construct&lt; _Ty,_Ty&gt;(std ::分配器&lt; _Ty&gt;&amp;,_ Objty *,_ V0_t&amp;&amp;)'正在编译

EDIT2:上面指出的用法不正确(正如安迪所指出的那样)。这是我的确切用法:

VertexEvaluator2f< Sphere3f, BasicVertexDX11::Vertex > evaluator;
evaluator.Evaluators.push_back( SurfacePositionFromSphere<BasicVertexDX11::Vertex>() );

在VertexEvaluator2f类中,我迭代属性以生成顶点。以下是该类的声明,为了完整性:

template <class TModel, class TVertex>
class VertexEvaluator2f
{
public:
    void SetModel( TModel& model ) {
        m_Model = model;
    };

    void evaluate( TVertex& v, float x, float y ) {
        for ( auto& evaluator : Evaluators ) {
            evaluator.evaluate( m_Model, v, x, y );
        }
    };

    std::vector< AttributeEvaluator2f< TModel, TVertex > > Evaluators;

protected:
    TModel m_Model;
};

1 个答案:

答案 0 :(得分:2)

  

所以问题是,是否有可能以这种方式覆盖抽象基类方法参数的类型?

是的,有可能。您的类的定义看起来是正确的,您可以看到它们正确编译here(我使用了一些虚拟VertexSphere3f类。)

问题很可能(或至少也是)这一行:

SurfacePositionFromSphere<BasicVertexDX11::Vertex> attribute();

实际上是声明名为attribute函数,它不接受任何参数并返回SurfacePositionFromSphere<BasicVertexDX11::Vertex>类型的对象。

当您稍后尝试访问该对象的成员函数时,编译器会抱怨(毕竟,您正在尝试访问函数指针的某些成员函数,这对编译器来说是无意义的)。

为了创建一个对象而不是声明一个函数,删除对象名称后的一对括号:

SurfacePositionFromSphere<BasicVertexDX11::Vertex> attribute;
//                                                          ^
//                                             No parentheses

<强>更新

您以这种方式声明属性向量:

std::vector< AttributeEvaluator2f< TModel, TVertex > > Evaluators;
与所有标准容器一样,

std::vector<>具有值语义。这意味着它将包含类型AttributeEvaluator2f< TModel, TVertex >的对象(而不是对象的指针!),并且该类确实是抽象的。

在这种情况下你想要的是使用(智能)指针,例如:

#include <memory>

template <class TModel, class TVertex>
class VertexEvaluator2f
{
    // ...

    void evaluate( TVertex& v, float x, float y ) {
        for ( auto& evaluator : Evaluators ) {
            evaluator->evaluate( m_Model, v, x, y );
        //           ^^
        }
    };

    std::vector<
        std::shared_ptr<AttributeEvaluator2f<TModel, TVertex>>
    //  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        > Evaluators;

protected:
    TModel m_Model;
};

这就是你如何向集合中添加元素:

VertexEvaluator2f< Sphere3f, BasicVertexDX11::Vertex > evaluator;
evaluator.Evaluators.push_back( 
    std::make_shared<SurfacePositionFromSphere<BasicVertexDX11::Vertex>>()
    );