纯虚拟成员函数必须处理模板化的缓冲区-如何处理
Pure virtual member function has to process a templated buffer - how to?
我有一个基类PixelBuffer,它有一个虚拟函数,可以将Pixel Buffer的内容复制到模板化的Buffer对象中。PixelBuffer可能有几个继承的实现,如OpenGLPixelBuffer/DXPixelBuffer,它们实现纯虚拟复制到缓冲区函数(伪代码):
class PixelBuffer
{
public:
virtual void copyToBuffer(? buffer) = 0; // how to declare this?
};
PixelBuffer有一个内部数据类型,可以是不同的基本类型(int、uint、float、char…)
更重要的是我要复制到的缓冲区的数据类型。缓冲区类(可能)看起来像这样:
template <typename T>
class Buffer
{
public:
Buffer() : m_data(), m_size(0) {}
Buffer(std::size_t buffsize) : m_data(new std::vector<T>(buffsize)), m_size(buffsize) { }
std::shared_ptr<std::vector<T>> data() { return m_data; }
std::size_t size() { return m_size; }
void allocate(std::size_t buffsize) {
m_data = std::shared_ptr<std::vector<T>>(new std::vector<T>(buffsize));
m_size = buffsize;
}
private:
std::shared_ptr<std::vector<T>> m_data;
std::size_t m_size;
};
typedef Buffer<float> FloatBuffer;
typedef Buffer<char> ByteBuffer;
我正在寻找一种方法来做这样的事情:
PixelBuffer* pbObj = ...;
FloatBuffer dest;
pbObj->copyToBuffer(dest); // does allocation and copying
由于不可能对PixelBuffer成员函数进行模板化,我现在不知道如何解决这个问题。我知道我需要很多实现来复制不同的缓冲区数据类型,但我不知道在哪里实现它们,也不知道如何在不向PixelBuffer(针对每种类型的缓冲区)添加一堆函数的情况下实现它们。
也许这可以使用访问者模式或策略来完成?
编辑:回答评论:是的,应该可以从任何PixelBuffer类型复制到任何Buffer类型。但是,应该只支持那些实现复制的类型!
我仍然不确定你需要什么,但如果你想通过Buffer
的各种专业化,那么你需要独特的方法,而不是单一的虚拟方法:
virtual void copyToBuffer(Buffer<char> & buffer) = 0;
virtual void copyToBuffer(Buffer<float> & buffer) = 0;
然后,您可能会在子类中重写这些,并可能在不支持复制操作的任何情况下抛出异常。你的问题表明你不想这样做,尽管我觉得如果你需要处理的缓冲专业有限,这是最好的解决方案。
如果你只想要一个方法,你需要将Buffer
的每个专业化所共有的功能抽象成一个每个专业化扩展的类,并引用它:
virtual void copyToBuffer(BufferBase & buffer) = 0;
template <typename T>
class Buffer : public BufferBase
{
// ...
在这种情况下,copyToBuffer
方法的实现将仅限于BufferBase
中提供的功能,所以我怀疑这个解决方案是否对您可行。
另一方面,如果你只想有一个接受特定类型缓冲区的方法,并且每个子类的类型不同,那么这个方法根本不应该在基类中声明——你应该在每个子类中用合适的参数类型来声明这个方法。在这种情况下,最干净的解决方案可能是根据PixelBuffer类所支持的缓冲区的元素类型对其进行参数化:
template <typename E>
class PixelBuffer : public PixelBufferBase
{
public:
virtual void copyToBuffer(Buffer<E> &) = 0;
}
你的例子变成:
PixelBufferBase* pbObj = ...;
PixelBuffer<float> *fpbObj = dynamic_cast<PixelBuffer<float> *>(pbObj);
FloatBuffer dest;
fpbObj->copyToBuffer(dest); // does allocation and copying
(出于性能考虑,您可能会使用static_cast
,但要牺牲一定的安全性)。
您实际上并不需要基于策略的设计;只有当copyToBuffer
实现可以在不同的PixelBuffer
子类之间共享(这听起来不太可能),并且在任何情况下您仍然需要参数化PixelBuffer
类型时,您才能从策略中获得好处。
我也不相信访问者模式能帮助你解决这个问题——它需要多个函数来处理多个PixelBuffer/Buffer类型;您可以将重载的方法转移到另一个类,但也不能避免对它的需要。
我也遇到过同样的问题。我使用void *
作为类型,并将指针转换为实现中正确的Buffer。它不漂亮,但它很有效,对表演没有任何影响。
但是,如果您的PixelBuffer
将复制到多个类型的Buffer
,而只有一个copyToBuffer
函数。您必须向不同类型的缓冲区添加另一个参数:
enum class BufferType
{
INT,
CHAR,
FLOAT,
//...
};
class PixelBuffer
{
public:
//....
virtual void copyToBuffer(void* buffer, BufferType buffertype) = 0;
}
virtual void DXPixelBuffer::copyToBuffer(void* buffer, BufferType buffertype)
{
switch(buffertype){
case BufferType::FLOAT:
Buffer<float>* pbuffer = static_cast<Buffer<float>*>(buffer);
//...
break;
//...
您可以使用traits类和wrap函数使对copyToBuffer
的调用更加安全。
template<typename T> struct BufferTraits;
template<> struct BufferTraits<float>{
static constexpr BufferType Type = BufferType::FLOAT;
};
template<> struct BufferTraits<char> {
static constexpr BufferType Type = BufferType::CHAR;
};
class PixelBuffer
{
public:
template<typename T> void PixelBuffer::copyToBuffer(Buffer<T>& buffer){this->copyToBuffer(reinterpret_cast<void *>(&buffer), BufferTraits<T>::Type);}
//...
}
您的示例将保持不变:)
PixelBuffer* pbObj = ...;
FloatBuffer dest;
pbObj->copyToBuffer(dest);
- 如何通过解析缓冲区并将数据放入正确的结构来处理传入的数据包连接?
- 跨平台套接字发送,Linux 上的缓冲区常量无效* Windows上的常量字符*,最佳处理方式
- 用于视频处理的图像缓冲区
- 处理第三方DLL的缓冲区溢出
- 如何处理C++中的通信缓冲区
- 使用统一缓冲区对象进行批处理渲染
- 是否有更好的方法来处理缓冲区和阅读中的不完整数据
- 0x00363A09处出现未处理的异常,堆栈cookie检测代码检测到基于堆栈的缓冲区溢出
- 为什么VxWorks中的缓冲区sendto()和send()函数的类型不同,以及我如何以相同的方式处理它们
- 如何在C++中处理完整的循环缓冲区
- OpenGL 批处理:为什么我的绘制调用超出了数组缓冲区边界
- 为什么套接字未正确处理此缓冲区大小
- 如何使用 std::hash 对缓冲区进行哈希处理
- 如何在 Direct3D11 中处理后台缓冲区
- 双缓冲区系统并发处理的设计
- 如果ioservice忙于处理回调,将在缓冲区中写入async_receive_from
- 纯虚拟成员函数必须处理模板化的缓冲区-如何处理
- 我可以处理一个isstrstream来获得对底层I /o缓冲区的随机搜索吗?
- 如何处理在使用libpd时不能被64整除的音频缓冲区大小
- 检查write()/send()是否可以处理整个缓冲区而不阻塞,否则失败(没有部分写入)