Если происходит приведение типа-наследника к одному из базовых типов, то это называется upcast. При таком приведении использование методов вида static_cast/dynamic_cast не требуется.
Обратное действие, когда происходит приведение базового типа к типу-наследнику, называется downcast. При таком приведении явный вызов методов xxx_cast обязателен.
При downcast вопрос только в том, какой каст применить. Быстрее - static_cast, но программист должен точно знать, что указатель/ссылка указывает на объект конкретного типа. Если программист ошибется - в рантайме может произойти все, что угодно. Если же программист не может знать, на что указывает указатель (например, метод возвращает объекты разных производных типов? уточнить) - придется использовать dynamic_cast, но он работает медленнее, ибо это элемент механизма RTTI (динамическая идентификация типа данных, Real Time Type Identification).
Примечание: в механизме RTTI, в принципе, имеется всего два инструмента: dynamic_cast<>() и typeid().
Пример кода:
// Объект Qt-класса QAbstractItemModel
QAbstractItemModel *base;
// Объект класса, унаследованного от QAbstractItemModel
TreeModel *child = new TreeModel;
// Upcast
base = child; // так можно (ибо child содержит все данные для base и даже больше)
// Downcast
child = base; // так, без преобразования, нельзя (base не имеет всех данных для child)
Еще один пример кода, демонстрирующий, что в памяти разворачивается объект производного класса, и указатель на этот объект свободно запоминается в указателе с типом базового класса. По этому указателю к производному классу разрешен только интерфейс базового класса. Тем не менее вся структура произвольного класса хранит в себе дополнительные данные, которые недоступны по ссылке на базовый класс.
Важно, что тем не менее, конструктор и деструктор производного класса вызываются. Конструктор вызывается потому, что командой "new Derv" все-таки создается объект класса Derv, хоть указатель на него и запоминается в указатель с типом базового класса. Деструктор вызывается потому, что у базового класса деструктор объявлен как виртуальные, и деструктор производного класса его переопределяет.
class Base
{
public:
virtual ~Base() { cout << "Base удален\n"; }
};
class Derv: public Base
{
public:
int *p;
Derv()
{
cout << "Derv - создается массив в куче\n";
p=new int[10];
}
~Derv()
{
cout << "Derv - удаляется массив в куче\n";
delete[] p;
}
void anyMethod()
{
cout << "Derv - anyMethod\n";
}
};
int main()
{
Base *pBase = new Derv;
// pBase->anyMethod(); // Будет ошибка компиляции
delete pBase;
return 0;
}