Проверка того, может ли работать перекрестный бросок? - PullRequest
8 голосов
/ 16 марта 2011

Я знаю, что разрешено использовать dynamic_cast для "перекрестного преобразования" по иерархии классов. Например, если у меня есть классы, которые выглядят так:

  A   B
   \ /
    C

Если у меня есть указатель A*, указывающий на объект типа C, тогда я могу использовать

A* aPtr = /* ... something that produces a C* ... */
B* bPtr = dynamic_cast<B*>(aPtr);

чтобы получить указатель на B базовый объект C, на который я указываю.

Причина, по которой я упоминаю это, заключается в том, что во время написания приведенного выше кода, возможно, что компилятор еще не видел определения C, хотя он видел A и B. Это означает, что возможно, что компилятор не обнаружит никакой связи между A и B, но ему все равно придется скомпилировать код в любом случае, потому что существует возможность существования класса, подобного C, и dynamic_cast чтобы преуспеть при некоторых обстоятельствах.

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

A   B    D
 \ /   
  C

Здесь D - некоторый случайный не связанный класс. Если я попытаюсь написать что-то вроде этого:

A* aPtr = /* ... get a C* pointer ... */
D* dPtr = dynamic_cast<D*>(aPtr);

Тогда этот dynamic_cast всегда будет сбой во время выполнения, так как нет никакого способа соединить A и D. Если я использую D случайно, потому что я намеревался использовать B, компилятор не даст мне никаких указаний на то, что у меня есть бессмысленное приведение.

Мой вопрос: есть ли способ заставить компилятор предупредить меня о том, что приведение всегда будет неудачным во время выполнения? Я был бы рад решению на уровне языка или некоторой настройке компилятора для любого крупного компилятора, который мог бы обнаружить это. Если есть внешний инструмент, это тоже хорошо; Я просто хочу знать, возможно ли отловить этот класс ошибок.

Ответы [ 3 ]

3 голосов
/ 16 марта 2011

Невозможно обнаружить это во время компиляции.Класс C, который вводит взаимосвязь, может быть найден в динамически загружаемой библиотеке, которая еще даже не была написана, и компилятор не может доказать обратное.

Хотя может быть несколько исключений.Если A имеет только приватные конструкторы (или приватный деструктор), то компилятор может быть уверен, что не будет новых подклассов, которые не названы друзьями как A.

0 голосов
/ 04 апреля 2017

В этом весь смысл динамического приведения: он динамический, т.е. проверяется во время выполнения, а не во время компиляции.

Компилятор проверяет только, являются ли приведенные классы полиморфными.Если классы не являются полиморфными, тогда не будет достаточно информации для проверки приведения во время выполнения.

И, наконец, после динамического приведения программа должна проверить, не является ли полученный указатель ненулевым.Если вы приведете к ссылке, вы должны поймать std :: bad_cast.

0 голосов
/ 16 марта 2011

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

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

...