Каковы недостатки «апкастинга»?

#c #virtual #abstract-class #upcasting

#c #виртуальный #абстрактный класс #апкастинг

Вопрос:

Цель абстрактного класса — не позволить разработчикам создать объект базового класса, а затем апкастировать его, AFAIK.

Теперь, даже если апкастинг не требуется, и я все еще использую его, оказывается ли это каким-то образом «невыгодным»?

Еще одно уточнение:
Из размышлений на C :

Часто при проектировании требуется, чтобы базовый класс представлял только интерфейс для своих производных классов. То есть вы не хотите, чтобы кто-либо на самом деле создавал объект базового класса, только для преобразования в него, чтобы можно было использовать его интерфейс. Это достигается путем придания этому классу абстрактного вида,

Под апкастингом я имел в виду: baseClass *obj = new derived ();

Комментарии:

1. Нет, это не доказывает disadvantageous , он использует принцип подстановки

2. static_cast<Base*>( pDerived ) является апкастом . Это то, что вы имели в виду?

3. Может быть, вы путаете приведение вверх и вниз? Апкастинг — это совершенно нормально и необходимо для работы полиморфизма.

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

5. @AlfP.Steinbach Под апкастингом я имел в виду baseClass *obj = new derived ();

Ответ №1:

Апкастинг может быть невыгоден для неполиморфных классов. Например:

 class Fruit { ... };  // doesn't contain any virtual method
class Apple : public Fruit { ... };
class Blackberry : public Fruit { ... };
  

переместите его куда-нибудь,

 Fruit *p = new Apple;  // oops, information gone
  

Теперь вы никогда не узнаете (без какого-либо ручного механизма), что if *p является экземпляром Apple или a Blackberry .

[Обратите внимание, что dynamic_cast<> это недопустимо для неполиморфных классов.]

Комментарии:

1. Спасибо, но я говорил только о полиморфных классах 🙂

2. @AnishaKaul, хорошо, я ответил на это, потому что этот момент не был упомянут в вашем вопросе. Кстати, для полиморфных классов апкастинг является важной функцией, он не может быть опасным.

Ответ №2:

Абстрактные классы используются для выражения концепций, которые являются общими для набора (под-) классов, но для которых нецелесообразно создавать экземпляры.

Рассмотрим класс Animal . Не имеет смысла создавать экземпляр этого класса, потому что нет ничего, что было бы просто animal . Существуют утки, собаки и слоны, каждый из которых является подклассом animal. Формально объявив класс animal, вы можете уловить сходства всех типов animals, а сделав его абстрактным, вы можете выразить, что его нельзя создать.

Апкастинг необходим для использования полиморфизма в статически типизированных языках. Это, как указал @Jigar Joshi в комментарии, называется принципом подстановки Лискова.

Редактировать: Апкастинг не является недостатком. На самом деле, вы должны использовать его, когда это возможно, чтобы ваш код зависел от суперклассов (интерфейсов) вместо базовых классов (реализаций). Это позволяет вам позже переключать реализации без необходимости изменять свой код.

Комментарии:

1. Я знаю значение абстрактного класса. Мой вопрос в том, является ли использование «upcasting» (когда не требуется) каким-то невыгодным способом?

2. @AnishaKaul: Я добавил абзац об этом.

3. извините, я не смог правильно понять making your code depend on super-classes(interfaces) instead of base-classes(implementations). Разве мы не говорили о базовых и производных классах? Что такое суперкласс и какова его функциональность?

4. суперкласс — это другое слово для базового класса, извините, что перепутал это.

5. Upcasting is not disadvantageous. In fact, you should use it whenever possible … при условии, что вы имеете дело с полиморфными классами.

Ответ №3:

Апкастинг — это технический инструмент.

Как и любой инструмент, он полезен при правильном использовании и опасен / невыгоден при непоследовательном использовании.

Это может быть хорошо или плохо в зависимости от того, насколько «чистым» вы хотите, чтобы ваш код соответствовал данной парадигме программирования.

Итак, C не обязательно является «чистым ООП», не обязательно «чисто универсальным», не обязательно «чисто функциональным». И поскольку C является «прагматичным языком», это, в общем, не является преимуществом, заставляющим его соответствовать «одной-единственной парадигме».

Единственное, что можно сказать в технических терминах, это то, что,

  • Производный класс — это базовый класс плюс нечто большее
  • Обращение к производному через базовый указатель делает это «нечто большее» недоступным, если только в базе не существует механизма, позволяющего перейти в производную область.
  • Механизм, который C предлагает для этого неявного перехода, — это виртуальные функции.
  • Механизм, предлагаемый C для явного перехода, является dynamic_cast (используется при нисходящей передаче).
  • Для неполиморфных объектов (у которых нет никакого виртуального метода) static_cast (для понижения) все еще доступен, но без проверки во время выполнения.

Преимущества и недостатки вытекают из последовательного и непоследовательного использования всех этих точек вместе. Это не вопрос, связанный только с downcast.

Ответ №4:

Одним из недостатков была бы очевидная потеря новой функциональности, введенной в производный класс:

 class A
{
   void foo();
}

class B : public A
{
   void foo2();
}

A* b = new B;
b->foo2(); //error - no longer visible
  

Я говорю здесь о невиртуальных функциях.

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

Однако всего этого можно избежать при хорошей архитектуре.

Комментарии:

1. Я не думаю, что этот пример объясняет недостаток апкастинга. foo2() является членом class B , а не class A нет, поэтому его никогда не было видно. Как только вы напишете невиртуальный A::foo2() , он будет виден в автоматическом режиме! ( Примечание : я не отклонил этот ответ)

2. @iammilind, именно моя точка зрения. Но b — это объект типа B… Я уже упоминал, что при хорошем дизайне это на самом деле не является препятствием.

3. @LuchianGrigore — ваша точка зрения верна, но ваш пример — нет. В случае вашего примера вы получаете обычную старую ошибку компиляции.