Trying to find the best design for this!
Note that we have the Image template class that inherits from the template matrix library (in this case Eigen, but it could be anything)
template <typename T> class Image : public Eigen::Matrix <T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>
Now think about what we want to write a function to handle reading images from a file. Of course, images can be of different types, that is, unisnged char, uint16_t, float, and even have different channels, like in grayscale, RGB, or even RGBA.
That way, we could, of course, use template classes to handle this easily. How in
Image<RGB<unisgned char>> or Image<RGBA<float>>
Simple when a person knows the type of image, say, monochrome 8bit
Image<unisgned char> image = ReadImage(const char* const filename);
or maybe even
Image<unisgned char> image; bool b = ReadImage(const char* const filename, Image<unisgned char>& image)
However, when reading an image file, we never know the type before reading the image. For example, Tiff and png support 8 bits and 16 bits with tiff support, even supporting float. In such cases, it is not possible to use any of the functions mentioned above. However, we can have a temmplate Factory class for sorting.
To do this, we first need to introduce the BaseImage class
class BaseImage { public: inline BaseImage() {}; virtual inline ~BaseImage() {}; virtual inline int Width() const = 0; virtual inline int Height() const = 0; virtual inline int Depth() const = 0; etc... }; template <typename T> class Image : public BaseImage, public Eigen::Matrix <T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>
Then we can have our Factory class, where we pass our unsigned char *, float *, etc. and let him handle the creation
class ImageFactory { typename <T> static BaseImage* createImage(const T* const src, const int& width, const int& height, const int& depth) { if (depth == 1) { return new Image<T>(); } else if (depth == 3) { return new Image<RGB<T>>(); } etc... } }
Of course, this makes me use dynamic allocation and inheritance.
I suppose I can get around the dynamic allocation by hiding it inside a class that takes care of this. In the constructor, Factory clas will be called
class Image2 { public: Image2(const char* const path) { // where ReadImage and external function that will call ImageFactory pBaseImage = ReadImage(path); } ~Image2(); private: BaseImage* pBaseImage; };
In any case, my BaseImage class will have to expose all the functionality I need to use in my matrix library, which does not match the purpose of inheritance.
The question is, is there a better design than you can use here, because it gets pretty bulky