static_cast для производных классов, когда база превращается из не полиморфной в полиморфную - PullRequest
2 голосов
/ 25 октября 2010

Я рассматриваю оператор приведения C ++ и у меня возникают следующие сомнения:

для полиморфных классов

  • II следует использовать polymorphic_cast
  • Я никогда не должен использоватьstatic_cast, поскольку принижение может привести к неопределенному поведению.Код все равно компилирует этот случай.

Теперь предположим, что у меня следующая ситуация

class CBase{};
class CDerived : public CBase{};

int main( int argc, char** argv ){
    CBase* p = new CDerived();
    //.. do something
    CDerived*pd = static_cast<CDerived*>( p );
}

Поскольку полиморфизм не задействован, я не буду использовать polymorphic_cast, и код будетдаже не компилировать.

Если в какой-то момент кто-то вводит некоторые функции virtual в дерево наследования, и теперь я знаю об этом, поэтому я в опасности: как я могу это реализовать?

Я должен перейти к polymorphic_cast, чтобы избежать какого-либо риска, но код все равно будет компилироваться без каких-либо уведомлений.

Что вы делаете, чтобы понять о таких изменениях или предотвратить эти случаи?

Спасибо AFG

Ответы [ 3 ]

3 голосов
/ 25 октября 2010

Фон, который вы не включили - boost имеет polymorphic_cast в качестве обёртки вокруг dynamic_cast<>, который выбрасывается при сбое приведения. static_cast<> хорошо, если вы уверены, что данные относятся к тому типу, к которому вы приводите ... нет проблем с виртуальными членами или без них, и код, который вы включаете, говоря, что он не будет компилироваться, будет компилироваться и выполняться просто отлично, как есть.

Полагаю, вы думаете о возможности случайного приведения к другому производному классу? В этом полезность / опасность литья, не так ли? Вы можете добавить виртуальный деструктор, а затем использовать dynamic_cast <>, так как, строго говоря, RTTI доступен только для типов с одной или несколькими виртуальными функциями.

Код, написанный с использованием static_cast <>, будет по-прежнему безопасно обрабатывать один и тот же тип независимо от внедрения виртуальных функций ... просто если вы начнете передавать этот код другим типам (то есть не CDerived или что-либо публично полученное из них), вы понадобится dynamic_cast <> или другое изменение для предотвращения несовместимых операций.

1 голос
/ 25 октября 2010

Пока вы работаете с указателем p (типа CBase *), указанный объект будет обрабатываться как CBase, но все виртуальные функции будут работать правильно.Pointer pd обрабатывает тот же объект, что и CDerived.Передача таким образом опасна, поскольку, если объект не является производным от переданного типа, любые дополнительные данные члена для переданного объекта будут отсутствовать (это означает, что вы будете искать в некоторых других данных), и поиск виртуальной функции будетвсе перепутано.Это противоположность понижению (как вы отметили этот вопрос), где вы можете получить нарезку .

Чтобы избежать этого, вам нужно изменить свой стиль программирования.Рассматривать один и тот же объект как два разных типа - сомнительная практика.C ++ может быть очень хорош в обеспечении безопасности типов, но он позволит вам избавиться от неприятных вещей, если вы действительно этого хотите или просто не знаете лучше.Если вы хотите делать разные вещи в зависимости от типа объекта и не можете делать это с помощью виртуальных функций (например, с помощью двойная диспетчеризация ), вам следует более подробно изучить RTTI ( смотрите здесь, или посмотрите несколько хороших примеров здесь ).

0 голосов
/ 25 октября 2010

polymorphic_cast не определен в C ++. Вы думаете о dynamic_cast?

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

...