钻石继承的解决方案,但是合适吗?
Solution to diamond inheritance, but is it appropriate?
除了我一直在做的其他各种事情,我还一直在制作图像 api。我遇到的一个问题是需要有一个包含图像尺寸的图像库 class。从它会分支出 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{
...
};
当然,现在它们是两个 vtable 指针和每个图像实例的变暗,我想考虑到像素数组的大小,这可能不值得担心,但是这有一些禁欲主义的不愉快,所以我设计了这个解决方案;
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{
...
};
现在,由于 ImageO 和 ImageI 中的某些运算符是私有的,因此无法从该类型的指针访问它们,这几乎完成了 class 的输入和输出版本所完成的工作。不过有一个小问题,转换语法现在有点复杂。
ImageI* myImgInput = static_cast<ImageI*>((ImageIO*)(&myReal));
我认为巧妙地使用转换函数可以使过程自动化,所以最后一个问题是,这是否存在任何固有缺陷?我已经用一个小的实现测试了它,它完全可以工作,但我不想完成 api,然后必须重新开始。
编辑
请注意,为了清楚起见,第二个示例中的 ImageBase 现在是 ImageIO,而第二个示例中的 ImageI 和 ImageO 不 应该实际上继承自 ImageIO
如果碱基有数据成员,这将无法工作
使用以下尺寸
Imagaebase=4
ImageI=12 + 4 from Imagebase
ImageO=24 + 4 from Imagebase
在第一个示例中,Bitmap
的大小为 4 + 12 + 24(注意 Imagebase 只计算一次)= 40
在第二种情况下,Bitmap
的大小为 4
如果尺寸如此歪斜,铸造将无法正常工作
如果类中没有数据则:
Base 应该是 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{
...
};
除了我一直在做的其他各种事情,我还一直在制作图像 api。我遇到的一个问题是需要有一个包含图像尺寸的图像库 class。从它会分支出 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{
...
};
当然,现在它们是两个 vtable 指针和每个图像实例的变暗,我想考虑到像素数组的大小,这可能不值得担心,但是这有一些禁欲主义的不愉快,所以我设计了这个解决方案;
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{
...
};
现在,由于 ImageO 和 ImageI 中的某些运算符是私有的,因此无法从该类型的指针访问它们,这几乎完成了 class 的输入和输出版本所完成的工作。不过有一个小问题,转换语法现在有点复杂。
ImageI* myImgInput = static_cast<ImageI*>((ImageIO*)(&myReal));
我认为巧妙地使用转换函数可以使过程自动化,所以最后一个问题是,这是否存在任何固有缺陷?我已经用一个小的实现测试了它,它完全可以工作,但我不想完成 api,然后必须重新开始。
编辑
请注意,为了清楚起见,第二个示例中的 ImageBase 现在是 ImageIO,而第二个示例中的 ImageI 和 ImageO 不 应该实际上继承自 ImageIO
如果碱基有数据成员,这将无法工作
使用以下尺寸
Imagaebase=4
ImageI=12 + 4 from Imagebase
ImageO=24 + 4 from Imagebase
在第一个示例中,Bitmap
的大小为 4 + 12 + 24(注意 Imagebase 只计算一次)= 40
在第二种情况下,Bitmap
的大小为 4
如果尺寸如此歪斜,铸造将无法正常工作
如果类中没有数据则:
Base 应该是 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{
...
};