Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
En C++, si una clase se deriva de una clase base que contiene una o varias funciones virtuales, se puede usar un puntero a ese tipo de clase base para llamar a funciones virtuales en el objeto de clase derivada. Una clase que contiene funciones virtuales se denomina a veces “clase polimórfica”.
Jerarquía de clases
Un objeto de tipo C se puede visualizar de la siguiente manera:
Clase C con subobjetos B y A
Dada una instancia de la clase C, hay un subobjeto B y un objeto A. La instancia de C, incluidos los subobjetos A y B, es el "objeto completo".
Dado que una clase derivada contiene completamente las definiciones de todas las clases base a partir de las que se deriva, es seguro convertir un puntero a cualquiera de sus clases base (un proceso conocido también como conversión a tipo básico). Dado un puntero a una clase base, puede ser seguro convertir el puntero a una instancia de una clase derivada (un proceso conocido también como conversión a tipo heredado).
Mediante el uso de información de tipos en tiempo de ejecución, es posible determinar si un puntero apunta realmente a un objeto completo y si se puede realizar una conversión segura para que apunte a otro objeto de su jerarquía. El operador dynamic_cast realiza una comprobación en tiempo de ejecución para asegurarse de que la operación es segura. Es mejor diseñar la jerarquía de clases para que pueda usar funciones virtuales para evitar la necesidad de convertir a un tipo heredado. Sin embargo, si debe convertir a un tipo heredado, use dynamic_cast para asegurarse de que la operación es segura.
Para la conversión de tipos que no son polimórficos, puede usar el operador static_cast (en este tema se explica la diferencia entre las conversiones estáticas y dinámicas, y cuándo es adecuado utilizar cada una de ellas).
El siguiente ejemplo muestra el uso de dynamic_cast y static_cast:
#include <iostream>
class Base {
public:
virtual void print() { std::cout << "Base\n"; }
};
class Derived1 : public Base {
public:
void print() override { std::cout << "Derived1\n"; }
};
class Derived2 : public Base {
public:
void print() override { std::cout << "Derived2\n"; }
};
class MostDerived : public Derived1, public Derived2 {
public:
void print() override { std::cout << "MostDerived\n"; }
};
int main() {
MostDerived md;
Base* b1 = static_cast<Derived1*>(&md); // Upcast to Derived1 is safe
Base* b2 = static_cast<Derived2*>(&md); // Upcast to Derived2 is safe
// Downcast to MostDerived is ambiguous and unsafe
// MostDerived* md1 = static_cast<MostDerived*>(b1); // This won't compile
// MostDerived* md2 = static_cast<MostDerived*>(b2); // This won't compile
// Correct way to downcast in this situation
MostDerived* md1 = dynamic_cast<MostDerived*>(b1); // This is safe
MostDerived* md2 = dynamic_cast<MostDerived*>(b2); // This is safe
md1->print(); // Prints "MostDerived"
md2->print(); // Prints "MostDerived"
return 0;
}
En esta sección se describen los temas siguientes: