C++ 钻石继承的解决方案,但它合适吗?

C++ 钻石继承的解决方案,但它合适吗?,c++,virtual-inheritance,diamond-problem,C++,Virtual Inheritance,Diamond Problem,除了我一直在做的其他事情外,我还制作了一个图像api。但我遇到的一个问题是需要一个包含图像维度的图像基类。它将把ImageIn和ImageOut分支出来,ImageIO就是从这些分支出来的。这是我最初的解决方案 class ImageBase{ public: point<int> Dim() const=0; }; class ImageI : virtual public ImageBase{ public: virtual unsigned int get(int x

除了我一直在做的其他事情外,我还制作了一个图像api。但我遇到的一个问题是需要一个包含图像维度的图像基类。它将把ImageIn和ImageOut分支出来,ImageIO就是从这些分支出来的。这是我最初的解决方案

class ImageBase{
public:
  point<int> Dim() const=0;
};

class ImageI : virtual public ImageBase{
public:
  virtual unsigned int get(int x, int y) const=0;
};

class ImageO : virtual public ImageBase{
public:
  virtual void set(int x, int y, unsigned int col)=0;
};

class ImageIO : public ImageI, public ImageO{
};

class Bitmap : public ImageIO{
  ...
};
class ImageIO{ // could also be called ImageBase
public:
  point<int> Dim() const=0;
  virtual unsigned int get(int x, int y) const=0;
  virtual void set(int x, int y, unsigned int col)=0;
};

class ImageI : public ImageIO{
public:
  point<int> Dim() const=0;
  virtual unsigned int get(int x, int y) const=0;
private:
  virtual void set(int x, int y, unsigned int col)=0;
};

class ImageO : public ImageIO{
public:
  point<int> Dim() const=0;
  virtual void set(int x, int y, unsigned int col)=0;
private:
  virtual unsigned int get(int x, int y) const=0;
};

class Bitmap : public ImageIO{
  ...
};
类ImageBase{
公众:
点尺寸()常数=0;
};
类ImageI:虚拟公共ImageBase{
公众:
虚拟无符号整数get(整数x,整数y)常量=0;
};
类ImageO:虚拟公共ImageBase{
公众:
虚空集(整数x,整数y,无符号整数列)=0;
};
类ImageIO:公共ImageI,公共ImageO{
};
类位图:公共图像IO{
...
};
当然,现在他们有两个vtable指针和DIM指向图像的每个实例,我假设给定一个像素数组的大小,可能不值得担心,但这有一些令人不快的地方,所以我使用这个解决方案

class ImageBase{
public:
  point<int> Dim() const=0;
};

class ImageI : virtual public ImageBase{
public:
  virtual unsigned int get(int x, int y) const=0;
};

class ImageO : virtual public ImageBase{
public:
  virtual void set(int x, int y, unsigned int col)=0;
};

class ImageIO : public ImageI, public ImageO{
};

class Bitmap : public ImageIO{
  ...
};
class ImageIO{ // could also be called ImageBase
public:
  point<int> Dim() const=0;
  virtual unsigned int get(int x, int y) const=0;
  virtual void set(int x, int y, unsigned int col)=0;
};

class ImageI : public ImageIO{
public:
  point<int> Dim() const=0;
  virtual unsigned int get(int x, int y) const=0;
private:
  virtual void set(int x, int y, unsigned int col)=0;
};

class ImageO : public ImageIO{
public:
  point<int> Dim() const=0;
  virtual void set(int x, int y, unsigned int col)=0;
private:
  virtual unsigned int get(int x, int y) const=0;
};

class Bitmap : public ImageIO{
  ...
};
类ImageIO{//也可以称为ImageBase
公众:
点尺寸()常数=0;
虚拟无符号整数get(整数x,整数y)常量=0;
虚空集(整数x,整数y,无符号整数列)=0;
};
I类图像:公共图像{
公众:
点尺寸()常数=0;
虚拟无符号整数get(整数x,整数y)常量=0;
私人:
虚空集(整数x,整数y,无符号整数列)=0;
};
类ImageO:公共ImageIO{
公众:
点尺寸()常数=0;
虚空集(整数x,整数y,无符号整数列)=0;
私人:
虚拟无符号整数get(整数x,整数y)常量=0;
};
类位图:公共图像IO{
...
};
现在,由于ImageO和ImageI中的某些运算符是私有的,因此无法从该类型的指针访问它们,从而实现了类的输入和输出版本所能实现的功能。不过有一个小问题,强制转换语法现在有点复杂了

ImageI* myImgInput = static_cast<ImageI*>((ImageIO*)(&myReal));
ImageI*myImgInput=static_cast((ImageIO*)(&myReal));
我在想,巧妙地使用铸造功能可以使过程自动化,所以最后一个问题是,这有没有内在的缺陷?我已经用一个小的实现对它进行了测试,它完全可以工作,但我不想完成api,然后必须重新开始

编辑
请注意,为了清晰起见,第二个示例中的ImageBase现在是ImageIO,第二个示例中的ImageI和ImageO不应实际继承自ImageIO

使用以下尺寸

Imagaebase=4
ImageI=12 + 4 from Imagebase
ImageO=24 + 4 from Imagebase
在第一个示例中,
位图的大小为4+12+24(注意Imagebase仅计数一次)=40

在第二种情况下,
位图的大小为4

如果尺寸如此歪斜,铸造将不起作用

如果任何类中都没有数据,则:

底座应为
ImageIO
,并具有所有功能

然后让
ImageI
ImageO
继承它,使不允许的函数成为私有函数。那么就不需要浇铸了

如下所示:

class ImageIO{
public:
  point<int> Dim() const=0;
  virtual unsigned int get(int x, int y) const=0;
  virtual void set(int x, int y, unsigned int col)=0;
};

class ImageI : virtual public ImageIO{
private:
  virtual void set(int x, int y, unsigned int col)
  {
        // Can't be called
  }
};

class ImageO : virtual public ImageIO{
private:
  virtual unsigned int get(int x, int y) const
  {
        // Can't be called
  }
};

class Bitmap : public ImageIO{
  ...
};
类图像IO{
公众:
点尺寸()常数=0;
虚拟无符号整数get(整数x,整数y)常量=0;
虚空集(整数x,整数y,无符号整数列)=0;
};
类ImageI:虚拟公共ImageIO{
私人:
虚空集(整数x,整数y,无符号整数列)
{
//叫不上
}
};
类ImageO:虚拟公共ImageIO{
私人:
虚拟无符号整数get(整数x,整数y)常量
{
//叫不上
}
};
类位图:公共图像IO{
...
};

我不明白,为什么ImageO比ImageI大?它们都不包含数据,它们只声明函数,由于它们的继承相似,我认为它们的宽度相同?我只是用-fdump class hierarchy编译了这里的代码,.class文件声明第一个示例的类ImageIO只有8字节宽,第二个示例中的版本只有四个字节宽。40字节宽是什么意思?@user4578093您没有明确说明基类必须没有数据,如果没有,请参阅编辑以获得解决方案。这正是第二个示例中的情况。ImageO->ImageBase,ImageI->ImageBase,位图->ImageBaseSo,您是否同意该结构?编辑是第二个问题,应该删除并作为新问题询问。注意,第二个示例中的类从来都不应该使用虚拟继承。看起来原始解决方案更好、更正确。这是怎么回事?第二个解决方案的大小是第一个解决方案的一半,并且可以包含第一个解决方案的所有功能。问题是什么?