2017-02-07 23 views
0

У меня есть для каждого цикла, который итерации над вектором указателей. указатели относятся к базовому классу. В каждом цикле я использую производный тип как тип итератора. Функция рендеринга определена только в некоторых из производных классов, но код компилируется и запускается ... Он сбрасывается, если вектор содержит указатель на производный объект, который не имеет функции рендеринга (очевидно).C++ для каждого, скрытый тип cast

for each (DerivedClass* body in myVector) 
{ 
    body->render(); 
} 

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

Может ли кто-нибудь сказать мне правильный способ поймать эту ошибку? Проверка нулевого указателя не работает.

+2

Вы уверены, что это C++? – SU3

+1

@ SU3, это более старый синтаксис MSVC, устаревший с тех пор, как они поддерживали стандартные диапазоны для циклов. – chris

+0

Похоже, что это просто 'static_cast' под капотом, поэтому вы не можете проверить posteriori. Как насчет итерации с помощью «BaseClass *» и downcasting вручную с помощью 'dynamic_cast'? – Quentin

ответ

1

Если я правильно вас понимаю, проблема в том, что только некоторые указатели в вашем векторе указывают на объекты, которые имеют тип, который реализует render(). Если это так, то dynamic_cast выполнит трюк проверки правильного типа.

for (DerivedClass *p : myVector) { 
    class_implementing_render *q = dynamic_cast<class_implementing_render>(p); 
    if (q) q->render(); 
} 
+0

Вы проверили это? –

3

Действительно, проблема в том, что цикл foreach Microsoft слишком разрешительный. Microsoft имеет осуждается это расширение в пользу стандартный диапазон на основе для цикла (так как C++ 11):

for (DerivedClass* body : myVector) { 
    body->render(); 
} 

Здесь глава цикла, не будет компилироваться, так как он не может инициализировать DerivedClass* от BaseClass*.

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

for (auto base : myVector) { 
    if (auto derived = dynamic_cast<DerivedClass*>(base)) { 
     derived->render(); 
    } 
} 

Не имею C++ 11 (который я могу только предположить, что из-за отсутствия стандартного цикла)? Вы можете использовать традиционный цикл for с индексами или итераторами. Вы также можете более подробно описывать типы в моем примере dynamic_cast.

Чтобы добавить немного вращения, иногда он появляется, когда этот тип литья является общим (например, некоторые реализации компилятора). Если это определено как хороший выбор дизайна, вы можете обернуть этот код в алгоритм. Например, вот как это выглядит в C#:

foreach (var body in myVector.OfType<DerivedClass>()) { 
    body.render(); 
}