Полезность ковариантных типов возврата в C ++ клон идиома? - PullRequest
4 голосов
/ 17 ноября 2010

Обычная идиома клона использует ковариантные типы возвращаемых данных:

struct Base {
    virtual Base* clone();
};

struct Derived : public Base {
    Derived* clone();
};

Я читал о том, что ковариантные типы возвращаемых данных были более поздним дополнением к C ++, и более старые компиляторы могут их не поддерживать.В этом случае класс Derived должен объявить свою функцию-член clone для возврата Base*.Поскольку, по-видимому, я использую Derived объекты только через Base указатели и / или ссылки при использовании этой идиомы, какова реальная польза / преимущество объявления типа возврата Derived*?

Также, связанный вопрос:

Я бы предпочел использовать умные указатели для выражения семантики передачи права собственности для подписи clone.Это невозможно при использовании ковариантных типов возврата, так как auto_ptr<Derived> не является ковариантным с auto_ptr<Base>.(Обратите внимание, что я не ищу лекцию об использовании умных указателей - auto_ptr просто используется в качестве примера здесь).Так в этом случае, есть ли причина не иметь Derived return auto_ptr<Base>?Есть ли лучший способ выразить семантику передачи права собственности?

Ответы [ 2 ]

3 голосов
/ 17 ноября 2010

Поскольку, предположительно, я использую производные объекты только через базовые указатели и / или ссылки при использовании этой идиомы ...

Вы ошибаетесь. Тот факт, что базовый класс существует, не означает, что вы всегда будете его использовать. Если у меня есть класс Shape с подклассами Circle и Rectangle, и у меня также есть класс Window. Я не собираюсь использовать Shape* для позиции и размера окна, когда я могу просто использовать Rectangle.

Для передачи права собственности вам все равно не следует использовать умные указатели. Я знаю, что вам не нужна лекция, но я не говорю, что умные указатели плохие, вы просто не должны использовать их в clone(). Вы не можете передать право собственности на то, что не имеет права собственности в первую очередь. Если кто-то хочет auto_ptr, он должен создать его с помощью клонированного необработанного указателя. То же самое касается других типов интеллектуальных указателей.

2 голосов
/ 17 ноября 2010

Это полезно, когда у вас есть указатель на Derived и вы хотите получить его клон:

Derived *ptr = ...;
Derived *clone = ptr->clone();

без ковариантных типов возврата, вы должны выполнить явное приведение:

Derived *clone2 = (Derived*)ptr->clone();

Обратите внимание, что Derived может быть базовым классом для еще более производных классов, в этом случае это имеет еще больший смысл.

К сожалению auto_ptr<Derived> и auto_ptr<Base> не являются ковариантными.Поэтому в этом случае вы должны возвращать один и тот же тип из всех функций клонирования.

...