При итерировании указателей на базовый тип контейнере и необходимости преобразования некого типа можно проверять указатель производного типа на ноль и вызывать любые методы (виртуальные и нет) (или обрабатывать исключение при работе с ссылкой).
Но при этом, из-за безопасности upcast возможна ситуация, когда указатель базового типа A преобразуется в указатель промежуточного типа B, при том что на самом деле указатель хранит адрес объекта C.
В ручной реализации rtti (пример из книги внизу) можно запретить такие изменения. Но dynamic_cast их не запрещает. Значит, зачем-то это нужно. Вопрос - почему?
#include <iostream>
class A {
public:
int data;
virtual ~A (void) { }
virtual void iam (void) { std::cout << "A \n"; }
};
class B : public A {
public:
virtual ~B (void) { }
virtual void iam (void) { std::cout << "B \n"; }
void special (void ) { std::cout << "B special \n"; }
};
class C : public B{
public:
virtual ~C(void) { }
virtual void iam (void) { std::cout << "C \n"; }
void special (void ) {std::cout << "C special \n"; }
};
int main(void) {
A * aptr = nullptr;
B * bptr = nullptr;
C * cptr = new C;
aptr = cptr;//good upcast
bptr = dynamic_cast<C *> (aptr);// good downcast and unwanted upcast
if (bptr){
bptr -> iam(); // C
bptr -> special(); // B special
}
delete cptr;
return 0;
}
class Metal : public Investment {
typedef Investment Super;
protected:
enum { OFFSET = 4, TYPEID = BASEID + OFFSET };
public:
virtual bool isA(int id) {
return id == TYPEID || Super::isA(id);
// return id == TYPEID ;
}
static Metal* dynacast(Security* s) {
return (s->isA(TYPEID)) ? static_cast<Metal*>(s) : 0;
}
};
for(vector<Security*>::iterator it = portfolio.begin();
it != portfolio.end(); ++it) {
Investment* cm = Investment::dynacast(*it);
if(cm)
cm->special();
else
cout << "not an Investment" << endl;
}