我正在尝试用C ++找到一个很好的继承解决方案。
我有一个Rectangle类和一个Square类。 Square类不能公开继承Rectangle,因为它不能完全满足矩形的要求。例如,一个Rectangle可以分别设置它的宽度和高度,当然这对于Square来说是不可能的。
所以,我的困境。 Square显然会与Rectangle共享很多代码;它们非常相似。
对于考试,如果我有类似的功能:
bool IsPointInRectangle(const Rectangle& rect);
它也适用于广场。事实上,我有很多这样的功能。
因此,在制作Square类时,我认为我会将私有继承与可公开访问的Rectangle转换运算符一起使用。所以我的方形类看起来像:
class Square : private Rectangle
{
public:
operator const Rectangle&() const;
};
但是,当我尝试将Square传递给IsPointInRectangle函数时,我的编译器只是在该上下文中抱怨“Rectangle是一个不可访问的基础”。我希望它能够注意到Rectangle运算符并使用它。
我正在尝试做什么?
如果这不起作用,我可能会将部分Rectangle重构为MutableRectangle类。
感谢。
答案 0 :(得分:6)
您可以制作课程ImmutableRectangle
,不需要任何更改器,只使用const
方法,您可以从中Rectangle
和ImmutableSquare
分别正确派生Square
和从那起,IS-A
。请注意,剪切可变性,const
关系确实保持 - 一个不可变的方形IS-A不可变矩形:可变性是唯一严重的问题,因此通过将其分解出来,您可以得到一些实质性代码重用(适用于所有const
用途 - 实际上不使用或需要可变性的用途。
只要没有(不可变)基类的类不变量依赖不可变性特征,就可以在继承中引入可变性。当然,可以从is
指针或对可变版本的引用正确构造不可变对象(可能在单独的内联友元函数中,以避免给基类提供对派生类的依赖;-)合理地 - 方便使用。
编辑:一条评论可以理解地表达了疑虑,因为“一个变量不是一个不可变的”:要理解这一点,你需要理解“IS-A”意味着什么 ...... 不表示Korzybski - 拒绝“身份NotNecessarilyMutableRectangle
”:表示LSP。通过约束的严格意义,这意味着:协方差,逆变,弱相等的前提条件,更强相等的后置条件等,因为它们适用于基础的 const 方法不可变的)和派生的(可变的)类。您将看到类不变量是唯一的问题,正如我在前一段中所提到的那样,所以只是避免将不变性断言为类不变量并且您处于三叶草中; - )。
可能有助于命名基类{{1}},因为它不会将断言不变性作为类不变量;这种非常精确的命名可能在哲学上令人放心,但在日常编码中可能有点不方便。
答案 1 :(得分:3)
你可以通过将一个矩形成为正方形并将其用于演员来解决你的问题:
class Square {
Rectangle r;
public:
operator const Rectangle&() const {
return r;
}
};
这应该编译和工作。我相信如果有的话,它不会给你更多的工作。
答案 2 :(得分:0)
我相信,虽然我不确定,你必须使用显式强制转换才能在该上下文中调用该转换运算符。 ImmutableRectangle
基础是一种常见且有效的解决方案。很相似,您可以使用更抽象的解决方案,例如:
/**
* Base for rectangular classes; name it whatever you want.
*/
class RectangularBase {
public:
virtual unsigned int getValue(int) const = 0;
};
/**
* Base for specific rectangular classes; also named whatever.
*/
template<unsigned int Dimensions>
class Rectangular : public RectangularBase {
public:
virtual unsigned int getValue(int index) const { return values[index]; }
private:
unsigned int values[Dimensions];
};
/**
* A square is Rectangular but has only one significant dimension.
*/
class Square : public Rectangular<1> {
public:
unsigned int getSideLength() const { return getValue(0); }
};
/**
* A Rectangle is Rectangular and has two significant dimensions.
*/
class Rectangle : public Rectangular<2> {
public:
unsigned int getWidth() const { return getValue(0); }
unsigned int getHeight() const { return getValue(1); }
};