处理模板创建的更好方法是什么?

xer*_*ion 6 c++ templates design-patterns c++11

试图找到一个更好的设计!

考虑到我们有一个模板Image类,它继承自模板矩阵库(在本例中是Eigen,但它可以是任何东西)

template <typename T>
class Image : public Eigen::Matrix <T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>
Run Code Online (Sandbox Code Playgroud)

现在想想我们想要编写一个函数来处理从文件中读取图像的情况.当然,图像可以是不同类型的,即unisnged char,uint16_t,float,甚至具有不同的通道,如灰度,RGB或甚至RGBA.

所以我们当然可以使用模板类来轻松处理这个问题

Image<RGB<unisgned char>> or Image<RGBA<float>>
Run Code Online (Sandbox Code Playgroud)

当人们知道图像的类型时,它很简单,比如单色8bit

Image<unisgned char> image = ReadImage(const char* const filename);
Run Code Online (Sandbox Code Playgroud)

或者它甚至可以

Image<unisgned char> image;
bool b = ReadImage(const char* const filename, Image<unisgned char>& image)
Run Code Online (Sandbox Code Playgroud)

然而,当读取图像文件时,我们在读取图像之前从不知道类型.例如,Tiff和png都支持8位和16位,tiff甚至支持浮点数.在这种情况下,不可能使用上述任何功能.但是,我们可以使用temmplate Factory类对其进行排序.

为此我们首先需要引入一个BaseImage类

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>
Run Code Online (Sandbox Code Playgroud)

然后我们可以使用我们的工厂类来传递我们的unsigned char*,float*等..并让它处理创建

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...
  }
}
Run Code Online (Sandbox Code Playgroud)

当然,这迫使我使用动态分配和继承.

我想我可以通过将它隐藏在一个负责它的类中来绕过动态分配.在构造函数中,将调用工厂clas

class Image2
{
public:
    Image2(const char* const path)
    {
        // where ReadImage and external function that will call ImageFactory
        pBaseImage = ReadImage(path);
    }
    ~Image2();

private:
    BaseImage* pBaseImage;
};
Run Code Online (Sandbox Code Playgroud)

在任何一种情况下,我的BaseImage类都必须公开我需要从我的矩阵库中使用的所有功能,这有点违背了继承的目的.

问题是,如果有一个比这里可以使用的更好的设计,因为它变得非常麻烦

Top*_*ort 1

如果我可以在评论中显示代码,我会将其作为评论发布...对我来说,这似乎很明显,您可能也想到了。为什么这不是您要找的东西?

class Image
{
public:
  Image (int bytesPerPixelIn = 1) { data_ = NULL; bytesPerPixel=bytesPerPixelIn;};

  void readImage (int width, int height);
private:
  int       bytesPerPixel_;
  void*     data_;
};

void Image::read (int width, int height, ...)
{
   data_ = new unsigned char [width*height*pixelSize(imageType_)];
   //...
}

//And you can inherit from this if need be to add special functions 
//like interleaving in BMP files
Run Code Online (Sandbox Code Playgroud)

编辑:好的,我明白了。这样效果会更好吗?

template <typename PixelType>
class Image
{
public:
  Image () { data_ = NULL; };

  virtual void allocateImage (int width, int height)
  {
    data_ = new PixelType [width*height]; 
  }
  virtual void readImage (int width, int height) = 0;
private:
  PixelType*     data_;
};

template <typename PixelType>
class ImageTIFF: public Image <PixelType> ...
Run Code Online (Sandbox Code Playgroud)

或这个:

template <typename PixelType, int WIDTH, int HEIGHT>
class Image
{
public:
  Image () { }

  virtual void readImage () = 0;
private:
  PixelType*     data_ [WIDTH][HEIGHT];
};

template <typename PixelType, int WIDTH, int HEIGHT>
class ImageTIFF: public Image <PixelType, WIDTH, HEIGHT> ...
Run Code Online (Sandbox Code Playgroud)

后者消除了动态内存...但没有动态内存,就无法拥有调整大小功能。我会使用动态内存。

当然,您需要继承不同的文件格式,因为它们读取图像的方式不同。

--

好的。这个怎么样?这里的 BaseImage 就像一个 Java“接口”,并且将确保派生类具有它们所需的功能。

class BaseImage 
{
public:
  virtual void allocateImage (int width, int height) = 0;
  virtual void readImage     (int width, int height) = 0;
};

template <typename PixelType>
class Image: public BaseImage ... /* and so on */

BaseImage* myTIFFImage = readTIFFImage (/* whatever goes here */);
Run Code Online (Sandbox Code Playgroud)