在 C9803 中
在 C++ 98/03 中封装 OpenGL 对象需要遵守 C++规则 3.这意味着添加复制构造函数,复制赋值运算符和析构函数。
但是,复制构造函数应该在逻辑上复制该对象。复制 OpenGL 对象是一件非常重要的事情。同样重要的是,它几乎肯定是用户不希望做的事情。
因此,我们将使对象不可复制:
class BufferObject
{
public:
BufferObject(GLenum target, GLsizeiptr size, const void *data, GLenum usage)
{
glGenBuffers(1, &object_);
glBindBuffer(target, object_);
glBufferData(target, size, data, usage);
glBindBuffer(target, 0);
}
~BufferObject()
{
glDeleteBuffers(1, &object_);
}
//Accessors and manipulators
void Bind(GLenum target) const {glBindBuffer(target, object_);}
GLuint GetObject() const {return object_;}
private:
GLuint object_;
//Prototypes, but no implementation.
BufferObject(const BufferObject &);
BufferObject &operator=(const BufferObject &);
};
构造函数将创建对象并初始化缓冲区对象的数据。析构函数将破坏对象。通过声明复制构造函数/赋值而不定义它们,如果任何代码试图调用它们,链接器将给出错误。通过宣称它们是私有的,只有 BufferObject
的成员甚至可以调用他们。
请注意,BufferObject
不会保留传递给构造函数的 target
。这是因为 OpenGL 缓冲区对象可以与任何目标一起使用,而不仅仅是最初创建的目标。这与纹理对象不同,纹理对象必须始终绑定到最初创建的目标。
因为 OpenGL 非常依赖于将对象绑定到上下文以用于各种目的,所以具有 RAII 样式的范围对象绑定通常也是有用的。因为不同的对象具有不同的绑定需求(一些具有目标,而另一些没有),我们必须分别为每个对象实现一个。
class BindBuffer
{
public:
BindBuffer(GLenum target, const BufferObject &buff) : target_(target)
{
buff.Bind(target_);
}
~BindBuffer()
{
glBindBuffer(target_, 0);
}
private:
GLenum target_;
//Also non-copyable.
BindBuffer(const BindBuffer &);
BindBuffer &operator=(const BindBuffer &);
};
BindBuffer
是不可复制的,因为复制它是没有意义的。请注意,它不会保留对它所绑定的 BufferObject
的访问权限。那是因为没必要。