es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Casteando la clase base a la clase derivada cuando la clase derivada solo agrega funciones no virtuales.

Supongamos que tengo algo similar a esto:

class Base {
public:
  Base(int value) : value(value) {}
  int getValue() const { return value; }
private:
  int value_;
};

class Derived : public Base {
public:
  // Derived solo tiene funciones no virtuales. No se agregaron miembros de datos adicionales.
  int getValueSquared() const { return value_ * value; }
};

Y hago lo siguiente:
Base* base = new Base(42);
Derived* derived = static_cast<derived*>(base);
std::cout << derived->getValueSquared() << std::endl;

Estrictamente hablando, esto es comportamiento indefinido (UB). Hablando en términos prácticos, funciona perfectamente.

Los miembros de datos reales de Base (por ejemplo, int value_) deben ubicarse en las mismas posiciones tanto si el objeto es realmente un Base como si es realmente un Derived (de lo contrario, buena suerte al realizar una conversión a un tipo superior). Además, getValueSquared() no forma parte de la huella de memoria real de una instancia de Derived, por lo que no es como si estuviera “ausente” o no construido a partir del objeto Base en memoria.

Sé que el comportamiento indefinido es suficiente razón para no hacer esto, pero lógicamente parece que siempre funcionaría. Entonces, ¿por qué no?

Pregunto esto porque parece ser una peculiaridad interesante para discutir…no porque tenga intención de usarlo en producción.</derived*>

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Aunque pueda funcionar en la práctica, acceder a un objeto de una clase derivada a través de un puntero a su clase base es un comportamiento indefinido en C++. El comportamiento de dicho código no puede ser predicho o garantizado por el estándar del lenguaje, y puede resultar en consecuencias inesperadas o peligrosas.

    Aunque parezca lógico que el desplazamiento de los miembros de datos en las clases base y derivadas deba ser el mismo, no hay nada que garantice esto en el estándar. De hecho, hay escenarios en los que esto puede no ser cierto. Además, el hecho de que getValueSquared() no forme parte de la disposición de memoria de un objeto de tipo Base significa que puede no construirse o inicializarse correctamente al ser accedido a través de un puntero a Base.

    Por lo tanto, aunque pueda funcionar en algunos casos, no se recomienda confiar en esta peculiaridad y el código debe ser escrito de manera que se adhiera al comportamiento definido en el estándar del lenguaje.

Comments are closed.