简体   繁体   English

C ++隐式转换运算符

[英]C++ Implicit Conversion Operators

I'm trying to find a nice inheritance solution in C++. 我试图在C ++中找到一个很好的继承解决方案。

I have a Rectangle class and a Square class. 我有一个Rectangle类和一个Square类。 The Square class can't publicly inherit from Rectangle, because it cannot completely fulfill the rectangle's requirements. Square类不能公开继承Rectangle,因为它不能完全满足矩形的要求。 For example, a Rectangle can have it's width and height each set separately, and this of course is impossible with a Square. 例如,一个Rectangle可以分别设置它的宽度和高度,当然这对于Square来说是不可能的。

So, my dilemma. 所以,我的困境。 Square obviously will share a lot of code with Rectangle; Square显然会与Rectangle共享很多代码; they are quite similar. 它们非常相似。

For examlpe, if I have a function like: 对于examlpe,如果我有这样的功能:

bool IsPointInRectangle(const Rectangle& rect);

it should work for a square too. 它应该适用于广场。 In fact, I have a ton of such functions. 事实上,我有很多这样的功能。

So in making my Square class, I figured I would use private inheritance with a publicly accessible Rectangle conversion operator. 所以在制作我的Square类时,我想我会使用一个可公开访问的Rectangle转换运算符的私有继承。 So my square class looks like: 所以我的方形类看起来像:

class Square : private Rectangle
{
    public:
        operator const Rectangle&() const;
};

However, when I try to pass a Square to the IsPointInRectangle function, my compiler just complains that "Rectangle is an inaccessible base" in that context. 但是,当我尝试将Square传递给IsPointInRectangle函数时,我的编译器只是在该上下文中抱怨“Rectangle是一个不可访问的基础”。 I expect it to notice the Rectangle operator and use that instead. 我希望它能够注意到Rectangle运算符并使用它。

Is what I'm trying to do even possible? 我正在努力做甚么可能吗?

If this can't work I'm probably going to refactor part of Rectangle into MutableRectangle class. 如果这不起作用,我可能会将 Rectangle的一部分重构为MutableRectangle类。

Thanks. 谢谢。

You can make a class ImmutableRectangle , without any mutators and with only const methods, from which you can correctly derive both Rectangle , and, separately, ImmutableSquare and, from that, Square . 你可以创建一个类ImmutableRectangle ,没有任何mutator和只有const方法,你可以从中正确地派生出Rectangle ,以及单独的ImmutableSquare以及SquareSquare Note that, shorn of mutability, the IS-A relationship does hold -- an immutable square IS-A immutable rectangle: mutability is the only serious issue, so by factoring it out you can get some substantial code reuse (for all const uses -- ones that don't in fact use, or need, mutability). 注意,在可变性方面, IS-A关系确实存在 - 一个不可变的方形IS-A不可变矩形:可变性是唯一严重的问题,因此通过将其分解出来,您可以获得一些实质性的代码重用(对于所有const用途 - - 实际上不使用或需要可变性的那些。

Introducing mutability along the inheritance is OK as long as no class invariants of the (immutable) base actually rely on the immutability characteristic; 只要没有(不可变)基类的类不变量实际上依赖于不变性特征,就可以在继承中引入可变性。 and of course an immutable object can be properly constructed from a const pointer or reference to the mutable version (presumably in a separate inline friend function to avoid giving the base class a dependency on the derived class;-) for reasonably-handy use. 当然,不可变对象可以从const指针或对可变版本的引用中正确构造(可能在单独的内联友元函数中,以避免使基类依赖于派生类;-)以便合理地使用。

Edit : one comment understandably expresses qualms because "a mutabe is not an immutable": to reason about this, you need to understand what "IS-A" means ... and it does not mean the Korzybski -denied " is of identity": it means the LSP . 编辑 :一个评论表示理解的疑虑,因为“一个mutabe不是一成不变”:来思考这一点,你需要了解什么是“IS-A” 是指 ......这并不意味着Korzybski -denied“ is身份的” :它表示LSP Go through the rigmarole of constraints this means: covariance, contravariance, weaker-equal preconditions, stronger-equal postconditions, etc, as they apply to the const methods of the base (immutable) and derived (mutable) classes. 经历约束的严格意义,这意味着:协方差,逆变,弱相等的前提条件,更强的平等后置条件等, 因为它们适用于基类(不可变)和派生(可变)类const方法 You'll see that class invariants are the only issue, as I mentioned in the previous paragraph, so just avoid asserting immutability as a class invariant and you're in clover;-). 您将看到类不变量是唯一的问题,正如我在上一段中所提到的那样,所以只是避免将不变性断言为类不变量并且您在三叶草中;-)。

Maybe it would help to name the base class NotNecessarilyMutableRectangle since it doesn't assert immutability as a class invariant; 也许它有助于命名基类NotNecessarilyMutableRectangle因为它没有将不变性断言为类不变量; that very precise naming might be philosophically reassuring but perhaps a trifle un-handy in everyday coding. 非常精确的命名可能在哲学上令人放心,但在日常编码中可能有点不方便。

Well, I'm surprised. 好吧,我很惊讶。 It seems privately inheriting a class A prevents you from using operator A outside the class. 似乎私有地继承A类会阻止您在类外使用运算符A.

You can solve your problem by making a member Rectangle for square and using it for the cast: 您可以通过为方形成一个矩形成员并将其用于强制转换来解决您的问题:

class Square {
    Rectangle r;
    public:
        operator const Rectangle&() const {
            return r;
        }
};

This should compile and work. 这应该编译和工作。 And I believe it won't give you that much more work to do if any. 我相信如果有的话,它不会给你更多的工作。

I believe, though I'm not certain, that you have to use an explicit cast to invoke that conversion operator in that context. 我相信,虽然我不确定,您必须使用显式强制转换来在该上下文中调用该转换运算符。 The ImmutableRectangle base is a common and effective solution. ImmutableRectangle基础是一种常见且有效的解决方案。 Quite similarly, you can use a more abstract solution such as: 很相似,您可以使用更抽象的解决方案,例如:

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

};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM