如何派生需要嵌套类的模板类型的模板类

How to derive a template class that needs a template type of a nested class?

本文关键字:嵌套 类型 何派生 派生      更新时间:2023-10-16

我正在使用OpenGL(C API(并将一些东西封装在类中。基本上,对glGenX的调用会生成GLuint,这些是实际创建的事物的句柄。清理时,应调用这些句柄上的glDeleteX

这意味着,对我来说,要有一个类

来保存这些(以及封装一些特定于它们的其他东西(并能够复制实例并传递它们,该类需要内部引用计数,以便它仅在没有更多引用时才调用glDeleteX

我已经做了两次了,我正在看第三节课。我可以看到我正在制作的很多课程都需要这个;所以我想使用模板来简化它。

下面是原始类的示例,其中引用计数仅在适当的时间调用glDeleteX

class Texture
{
public:
    Texture(const GLuint texture) : m_data(new Data(texture)) {}
    Texture(const Texture& t) : m_data(t.m_data) { ++m_data->m_count; }
    Texture(Texture&& t) : m_data(t.m_data) { ++m_data->m_count; }
    ~Texture() { if(--m_data->m_count == 0) delete m_data; }
    void Bind(GLenum target, GLint location) const { /* do some stuff */;
    void Release() const { /* do some stuff */
    GLuint GetTexture() const { return m_data->m_texture; }
private:
    class Data
    {
    public:
        Data(const GLuint texture) : m_count(1), m_texture(texture) {}
        Data(const Data& data) : m_count(1), m_texture(data.m_texture) {}
        ~Data() { glDeleteTexture(1,&m_texture); }
        GLuint m_texture;
        unsigned int m_count;
    };
    Data* m_data;
};

这是我尝试将其模板化:

template<typename... Ts>
class ReferenceCountedObject
{
public:
    ReferenceCountedObject(const Ts... args)
    :
        m_data(new Data(args...))
    {}
    ReferenceCountedObject(const ReferenceCountedObject& h)
    :
        m_data(h.m_data)
    {
        ++m_data->m_count;
    }
    ReferenceCountedObject(ReferenceCountedObject&& h)
    :
        m_data(h.m_data)
    {
        ++m_data->m_count;
    }
    virtual ~ReferenceCountedObject()
    {
        if(--m_data->m_count == 0)
            delete m_data;
    }
protected:
    class Data
    {
    public:
        Data(const Ts... args)
        :
            m_count(1),
            m_dataMembers(args...)
        {
        }
        Data(const Data& data)
        :
            m_count(1),
            m_dataMembers(data.m_dataMembers)
        {
        }
        virtual ~Data()
        {
            std::cout << "deleting base" << std::cout;
        }
        std::tuple<Ts...> m_dataMembers;
        unsigned int m_count;
    };
    Data* m_data;
};

这个想法是,内部 Data 类可能只需要一个GLuint句柄用于类Texture,但对于另一种类型,它可能需要三个不同的句柄。所以,这就是为什么有内部tuple

现在,我遇到了问题。这是我现在从这个模板化类派生的原始类:

class Texture : public ReferenceCountedObject<GLuint>
{
public:
    Texture(GLuint texture) : ReferenceCountedObject(texture) {}
    Texture(const Texture& t) : ReferenceCountedObject(t) {}
    Texture(Texture&& t) : ReferenceCountedObject(t) {}
    void Bind(GLenum target, GLint location) const { /* does that stuff */}
    void Release() const { /* does that stuff */ }
    GLuint GetTexture() const { return std::get<0>(m_data->m_dataMembers); }
protected:
};

如何定义基类Data的析构函数?到目前为止,我已经尝试这样做:

稍微更改基类:

template<class DataType, typename... Ts>
class ReferenceCountedObject
{
    /* ... */
protected:
    DataType* m_data;
};

因此,通过这种方式,您可以提供数据类型并覆盖虚拟析构函数:

class Texture : public ReferenceCountedObject<Texture::TData,GLuint>
{
    /* ... */
protected:
    class TData : public ReferenceCountedObject::Data
    {
    public:
        ~TData()
        {
            std::cout << "deleting derived" << std::cout;
            glDeleteTextures(1,&std::get<0>(m_dataMembers));
        };
    };
}

但我不能用Texture::TData实例化ReferenceCountedObject TData因为这是我试图定义的一部分。

我怎样才能正确地做到这一点?我承认我可能以一种完全不正确的方式去做这件事。

为什么不直接使用shared_ptr?这也是引用计算,并且传递起来更简单。您的类只需要处理分配和释放纹理,shared_ptr会在正确的时间进行重新计数和自动删除。另外,这使您可以免费使用弱指针。

您可以定义内部纹理类,然后执行

typedef std::shared_ptr<internal::Texture> Texture;

以便外部用户仅使用引用计数纹理。