关于为指向运行时确定的许多结构之一的指针构造类的建议 我正在编写一个位图(BPM)解析器,以在我学习的时候练习C++。然而,版本上有许多不同的图像标题,我碰到了一堵墙,围绕着如何实现这一点,我觉得这是一种避免了许多检查的方式,而且很优雅。你能就以下几种方法给我一些建议或建议其他方法吗
以下是我想到的方法。我遇到问题的主要原因是我想使用关于为指向运行时确定的许多结构之一的指针构造类的建议 我正在编写一个位图(BPM)解析器,以在我学习的时候练习C++。然而,版本上有许多不同的图像标题,我碰到了一堵墙,围绕着如何实现这一点,我觉得这是一种避免了许多检查的方式,而且很优雅。你能就以下几种方法给我一些建议或建议其他方法吗,c++,pointers,struct,encoding,bmp,C++,Pointers,Struct,Encoding,Bmp,以下是我想到的方法。我遇到问题的主要原因是我想使用memcpy来避免单独复制每个字段。结构之间唯一一致的是定义头/结构大小的前4个字节 在类中使用多个指针。在初始化时将每个参数设置为nullptr。然后使用一个reinterpret\u cast来确定第一次解析文件时要使用的头。从那时起,检查哪个指针不是nullptr,以确定使用哪个指针 在执行获取或设置标题中的值的操作时,使用void ptr并使用重新解释\u cast。也许不是最好的选择,但它就在那里 创建一个(我不确定我是否完全理解)。将
memcpy
来避免单独复制每个字段。结构之间唯一一致的是定义头/结构大小的前4个字节
reinterpret\u cast
来确定第一次解析文件时要使用的头。从那时起,检查哪个指针不是nullptr,以确定使用哪个指针重新解释\u cast
。也许不是最好的选择,但它就在那里memcpy
中顺利运行,因为据我所知,使用虚拟方法会在结构的开头添加一个不可见的指针,它会使用未修改的缓冲区直接将其覆盖到结构中而中断。(如果我错了,请告诉我)\ifndef位图\u包括
#定义位图\u H\u包含
#包括
#包括
#包括
#包括
枚举标题
{
文件=14,
核心=12,
InfoV1=40,
OS2=64,
InfoV4=108,
InfoV5=124,
};
枚举信息压缩方法
{
//为简洁起见省略
};
枚举半色调算法
{
//为简洁起见省略
};
结构文件头
{
//为简洁起见省略,第一个标头始终为14字节
};
结构核心头
{
uint32_t收割台尺寸;
uint16_t宽度;
uint16_t高度;
uint16_t平面;
uint16位深度;
};
结构InfoV1Header
{
uint32_t收割台尺寸;
int32_t宽度;
int32_t高度;
uint16_t平面;
uint16位深度;
uint32_t压缩;
uint32尺寸图像;
int32_t x_分辨率;
int32_t y__分辨率;
uint32使用的颜色;
uint32颜色很重要;
};
结构OS2Header:公共InfoV1Header
{
uint16分辨率单位;
uint16保留;
uint16\u t填充方向;
uint16_t半色调算法;
uint32半色调参数1;
uint32半色调参数2;
uint32_t颜色编码;
uint32应用程序定义;
};
结构InfoV4Header:公共InfoV1Header
{
uint32红色遮罩;
uint32绿色遮罩;
uint32_t蓝色_面具;
uint32阿尔法掩模;
uint32_t cs_型;
uint64_t红色_x;
uint64红色;
uint64_t red_z;
uint64绿色;
uint64绿色;
uint64_t绿色_z;
uint64_t蓝色_x;
uint64_t蓝色_u u y;
uint64_t蓝色_z;
uint32_t伽马红;
uint32_t伽马绿;
uint32_t伽马_蓝;
};
结构InfoV5Header:公共InfoV4Header
{
uint32_t意图;
uint32剖面图数据;
uint32剖面尺寸;
uint32保留;
};
类位图
{
公众:
位图(路径中的std::字符串);
~Bitmap();
无效保存(标准::字符串输出路径);
私人:
文件头*文件头;
//信息标题选项
核心头*核心头;
os2头*os2_头;
InfoV1Header*info\u v1\u header;
Infov4头*Infov4头;
InfoV5头*InfoV5头;
void verify_file_header()常量;
};
#endif/*位图包含*/
现在看起来似乎是最好的选择,但我对编写一系列方法的想法感到畏缩,这些方法从检查信息头中的nullptr开始。希望我错过了一些东西,因为我不太了解C++。
(目前在c++14中工作,但如果有意义的话,不反对使用17。在Linux Zorin OS 15上,使用gcc 7.4和cmake 3.15.2。)一个随机无关点,V4头中的红色x到蓝色z字段是32位有符号整数,而不是上面的64位UINT(实际上,它们是FXPT2DOT30类型-具有2位整数部分的定点,30位十进制) 处理此问题的典型方法是将整个BMP文件加载到一个大内存块中,然后重新解释数据。正如您所注意到的,V5派生自V4,V4派生自V1。考虑到决定文件中头类型的是头的大小,您可以执行穷人的动态转换。。。。
结构信息头;
结构OS2Header;
结构信息头;
结构InfoV5Header;
结构InfoV1Header
{
uint32_t收割台尺寸;
int32_t宽度;
int32_t高度;
uint16_t平面;
uint16位深度;
uint32_t压缩;
uint32尺寸图像;
int32_t x_分辨率;
int32_t y__分辨率;
uint32使用的颜色;
uint32颜色很重要;
模板
内联常量T*as()常量;
};
结构OS2Header:公共InfoV1Header
{
uint16分辨率单位;
uint16保留;
uint16\u t填充方向;
uint16_t半色调算法;
uint32半色调参数1;
uint32半色调参数2;
uint32_t颜色编码;
uint32应用程序定义;
};
结构InfoV4Header:公共InfoV1Header
{
uint32红色遮罩;
uint32绿色遮罩;
uint32_t蓝色_面具;
uint32阿尔法掩模;
uint32_t cs_型;
int32_t red_x;
int32_t red_y;
int32_t red_z;
int32_t绿色_x;
国际绿色联盟;
int32_t green_z;
int32_t blue_x;
int32_t blue_y;
int32_t blue_z;
uint32_t伽马红;
uint32_t伽马绿;
uint32_t伽马_蓝;
};
结构InfoV5Header:公共InfoV4Header
{
uint32_t意图;
uint32剖面图数据;
uint32剖面尺寸;
uint32保留;
};
模板
内联常量OS2Header*InfoV1Header::as()常量
{
返回标头_size==sizeof(OS2Header)?(const OS2Header*)此:0;
}
模板
内联常量InfoV4Header*Info
void doStuff(const InfoV1Header* v1)
{
// do stuff with the v1 fields
if(const OS2Header* os2 = v1->as<OS2Header>())
{
// do stuff with os2 fields
}
if(const InfoV4Header* v4 = v1->as<InfoV4Header>())
{
// do stuff with v4 fields
}
if(const InfoV5Header* v5 = v1->as<InfoV5Header>())
{
// do stuff with v5 fields
}
}