C ++隐式转换运算符

时间:2010-03-20 15:02:39

标签: c++ inheritance reference

我正在尝试用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类。

感谢。

3 个答案:

答案 0 :(得分:6)

您可以制作课程ImmutableRectangle,不需要任何更改器,只使用const方法,您可以从中RectangleImmutableSquare分别正确派生Square和从那起,IS-A。请注意,剪切可变性,const关系确实保持 - 一个不可变的方形IS-A不可变矩形:可变性是唯一严重的问题,因此通过将其分解出来,您可以得到一些实质性代码重用(适用于所有const用途 - 实际上不使用或需要可变性的用途。

只要没有(不可变)基类的类不变量依赖不可变性特征,就可以在继承中引入可变性。当然,可以从is指针或对可变版本的引用正确构造不可变对象(可能在单独的内联友元函数中,以避免给基类提供对派生类的依赖;-)合理地 - 方便使用。

编辑:一条评论可以理解地表达了疑虑,因为“一个变量不是一个不可变的”:要理解这一点,你需要理解“IS-A”意味着什么 ...... 表示Korzybski - 拒绝“身份NotNecessarilyMutableRectangle”:表示LSP。通过约束的严格意义,这意味着:协方差,逆变,弱相等的前提条件,更强相等的后置条件等,因为它们适用于基础的 const 方法不可变的)和派生的(可变的)类。您将看到类不变量是唯一的问题,正如我在前一段中所提到的那样,所以只是避免将不变性断言为类不变量并且您处于三叶草中; - )。

可能有助于命名基类{{1}},因为它不会将断言不变性作为类不变量;这种非常精确的命名可能在哲学上令人放心,但在日常编码中可能有点不方便。

答案 1 :(得分:3)

嗯,我很惊讶。似乎私有地继承A类会阻止您在类外使用运算符A.

你可以通过将一个矩形成为正方形并将其用于演员来解决你的问题:

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); }

};