我计划开发一个可以用C ++加载和处理图像文件的系统。在对系统进行编码之前,我想关注项目的软件工程和OOP方面。
我的问题是你如何设计这个系统的基本图像加载部分?这是我的班级结构:
在image.hpp文件中,我想要一个包含基本内容的类来表示内存中的所有图像文件。
// image.hpp
class image {
private:
unsigned int size;
protected:
unsigned int width;
unsigned int height;
uint8_t * raw;
public:
image();
image(const image& obj);
unsigned int getWidth() { return width; }
unsigned int getHeight(){ return height; }
virtual ~image();
virtual bool load(const std::string &fileName) = 0;
};
在tga.hpp文件中,我完全专注于TGA特定的操作。
// tga.hpp
typedef struct {
uint8_t idLength;
uint8_t colorMapType;
uint8_t imageType;
uint16_t colorMapOrigin;
uint16_t colorMapLength;
uint8_t colorMapDepth;
uint16_t xOrigin;
uint16_t yOrigin;
uint16_t width;
uint16_t height;
uint8_t bitsPerPixel;
uint8_t imageDescriptor;
} tgaHeader;
class tga: public image {
private:
tgaHeader header;
protected:
public:
bool load(const std::string &fileName);
};
你认为这是一个好方法吗? - 我不这么认为......
顺便说一句,我在问这个问题之前试图找到一个例子,但我甚至找不到一个关键词来阅读关于这些问题的文章。提前致谢!
答案 0 :(得分:0)
我建议将加载器外部化,使其分离并在抽象的“图像”类之外。客户可能会期望他在这个抽象级别看到的任何公共“加载”功能都能够加载一定数量的支持图像格式,而不会改变每个“图像”子类型的功能。
理由:您可能希望能够加载各种图像格式,并且可能不希望处理在每个可能的“图像”子类型中处理每种可能格式的痛苦。
如果您遇到像TGA这样的特定文件格式应该构造'tga'实例并且需要理解这个'tga'类的内部细节的情况,我建议采用非虚拟方法,例如允许构建'tga'通过参数化构造函数使用tga文件。
最后,如果你需要一个通用的“加载任何”函数,你可以使用类外的工厂方法创建它:
unique_ptr<image> load_image(const string& file)
{
if (extension_of(file) == "tga")
return unique_ptr<image>(new tga(file));
...
}
当然,如果您愿意,也可以将其作为“图像”类的静态方法或其他“image_loader”类。
如果你想要一个可扩展的加载器设计,那么你可以开始将文件格式扩展/标题信息映射到函数对象,这些函数对象根据传入的文件或文件数据返回一个新图像。然后你可以避免修改这个中心'load_image '每次提供新图像类型并支持新格式时都会运行。
在任何情况下,如果找不到为覆盖它的每个子类提供有意义且一致的行为的好方法,请尝试避免使用虚方法。如果你想更快地建立更稳定(不变的)设计,寻找不在公共界面中包含某些内容的理由并寻求将其添加到其他地方通常也很有用。
答案 1 :(得分:0)
我会质疑是否需要定义包含标题信息的子类图像。大多数库只有一个包含像素值和尺寸大小的图像对象。如果需要,您可以使用辅助函数返回标头结构。
如果我们查看CImg,它有一个load方法来检查扩展并调用适当的loader方法。然后,加载程序设置数据和大小成员。