C++ неявные операторы преобразования

Я пытаюсь найти хорошее решение для наследования в C++.

У меня есть Прямоугольный класс и Квадратный класс. Квадратный класс не может публично наследоваться Прямоугольнику, потому что он не может полностью выполнить требования прямоугольника. Например, Прямоугольник может иметь, это - ширина и высота каждый набор отдельно, и это, конечно, невозможно с Квадратом.

Так, моя дилемма. Квадрат, очевидно, совместно использует много кода с Прямоугольником; они весьма схожи.

Для примера, если у меня есть функция как:

bool IsPointInRectangle(const Rectangle& rect);

это должно работать на квадрат также. На самом деле у меня есть тонна таких функций.

Таким образом в создании моего Квадратного класса, я полагал, что буду использовать частное наследование с публично доступным Прямоугольным оператором преобразования. Таким образом, мой квадратный класс похож:

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

Однако, когда я пытаюсь передать Квадрат функции IsPointInRectangle, мой компилятор просто жалуется, что "Прямоугольник является недоступной основой" в том контексте. Я ожидаю, что это заметит оператор Rectangle и использование это вместо этого.

То, что я пытаюсь сделать даже возможный?

Если это не может работать, я, вероятно, собираюсь осуществить рефакторинг часть Прямоугольника в класс MutableRectangle.

Спасибо.

6
задан Imbue 20 March 2010 в 15:02
поделиться

3 ответа

Что ж, я удивлен. Кажется, частное наследование класса A не позволяет вам использовать оператор A вне класса.

Вы можете решить вашу проблему, сделав элемент Rectangle вместо квадрата и используя его для приведения:

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

Это должно скомпилироваться и работать. И я считаю, что это не даст вам столько работы, если таковая будет.

4
ответ дан 9 December 2019 в 22:32
поделиться

Вы можете создать класс ImmutableRectangle без каких-либо мутаторов и с помощью только методов const , из которых можно правильно получить как Rectangle , так и отдельно, ImmutableSquare и, следовательно, Square . Обратите внимание, что, исключая изменчивость, отношение IS-A выполняется - неизменный квадрат. Неизменяемый прямоугольник IS-A: изменчивость - единственная серьезная проблема, поэтому, вычленив ее, вы может получить существенное повторное использование кода (для всех const применений - тех, которые на самом деле не используют или не нуждаются в изменчивости).

Введение изменчивости в процессе наследования - это нормально, пока никакие инварианты класса (неизменяемой) базы на самом деле не полагаются на характеристику неизменяемости; и, конечно же, неизменяемый объект может быть правильно сконструирован из указателя const или ссылки на изменяемую версию (предположительно в отдельной встроенной функции друга, чтобы избежать зависимости базового класса от производного класса ;-) для разумно-удобное использование.

Править : один комментарий по понятным причинам выражает сомнения, потому что «мутабе не является неизменным»: чтобы рассуждать об этом, вам нужно понять, что означает «IS-A» ... и это не означает, что Коржибски -отрицание « есть идентичности»: это означает LSP .Пройдите через эту банальность ограничений, это означает: ковариантность, контравариантность, предварительные условия более слабого равенства, постусловия более сильного равенства и т. Д. применительно к методам const базы (неизменяемые) и производные (изменяемые) классы. Вы увидите, что инварианты классов - единственная проблема, как я упоминал в предыдущем абзаце, поэтому просто избегайте утверждения неизменяемости как инварианта класса, и вы в клевере ;-).

Возможно, было бы полезно назвать базовый класс NotNecessuallyMutableRectangle , поскольку он не утверждает неизменяемость как инвариант класса; это очень точное наименование может быть философски обнадеживающим, но, возможно, немного бесполезным в повседневном кодировании.

7
ответ дан 9 December 2019 в 22:32
поделиться

Я считаю, хотя и не уверен, что вы должны использовать явное приведение, чтобы вызвать этот оператор преобразования в этом контексте. База 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); }

};
0
ответ дан 9 December 2019 в 22:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: