¿Es legal este código?
class Base1 {
};
class Base2 {
public:
virtual ~Base2() {
if (!dynamic_cast<Base1*>(this))
std::cout << "aaaa" << std::endl;
}
Base2() {
}
};
class MyClass: public Base1, public Base2 {
public:
MyClass() {
}
virtual ~MyClass() {
std::cout << "bbb" << std::endl;
}
};
int main() {
MyClass s;
return 0;
}
Veo ambas impresiones pero debería ver solo una. Supongo que el elenco dinámico está mal. ¿Es posible hacer un control de este tipo?
c++
polymorphism
destructor
multiple-inheritance
dynamic-cast
greywolf82
fuente
fuente

!dynamic_castcomporta de manera diferente en constructores y destructores?Respuestas:
Tal vez encontré la solución yo mismo, la respuesta es no, no es posible:
De la viñeta 6 de la documentación de cppreference.com :
Ver también [class.cdtor] / 6 del estándar.
Como estoy enviando a Base1 en el destructor de Base2, este comportamiento no está definido.
fuente
[class.cdtor]/6, para referencia. Lo sentimos, no 5. Era 5 en C ++ 17 (borrador N4659), parece que es/6ahora.thises del tipo del destructor, por lo que no veo que UB se aplique. Sin embargo, el mismo párrafo estándar dice que el tipo más derivado del objeto bajo destrucción se considerará la clase del destructor, de modo que se observa el comportamiento explicado en la otra respuesta.Estoy de acuerdo con la respuesta de @ j6t, pero aquí hay un razonamiento ampliado con referencias estándar.
El comportamiento especial de los
dynamic_castobjetos en construcción y destrucción se describe en [class.cdtor] / 5 del estándar C ++ 17 (borrador final) y de manera equivalente en las versiones estándar anteriores.En particular dice:
El comportamiento indefinido no se aplica aquí, ya que el operando es la expresión
this, que trivialmente tiene el tipo de un puntero a la propia clase del destructor, ya que aparece en el destructor mismo.Sin embargo, la primera oración establece que
dynamic_castse comportará como si*thisfuera un objeto de tipo más derivadoBase2y, por lo tanto, la conversión aBase1nunca puede tener éxito, yaBase2que no se deriva deBase1, ydynamic_cast<Base1*>(this)siempre devolverá un puntero nulo, resultando en el comportamiento que está viendo.cppreference.com afirma que el comportamiento indefinido ocurre si el tipo de destino del molde no es el tipo de la clase del destructor o una de sus bases, en lugar de que esto se aplique al tipo de operandos. Creo que eso es solo un error. Probablemente, la mención de " nuevo tipo " en el punto 6 se suponía que debía decir " expresión ", lo que haría que coincidiera con mi interpretación anterior.
fuente
El
dynamic_castestá bien definido en esta situación. Es correcto que observe ambas líneas de salida.Se equivoca al suponer que en el destructor de
Base2thises una clase derivada. En este momento, la parte de la clase derivada ya se ha destruido, por lo que ya no puede ser una clase derivada. De hecho, en el momento en que seBase2ejecuta el destructor de , el objeto señalado porthises solo unBase2objeto. ComoBase2no está relacionado deBase1ninguna manera,dynamic_castdevuelve un puntero nulo y el condicional se ingresa en consecuencia.Editar: El estándar dice :
El operando se
thisrefiere al objeto bajo destrucción. Por lo tanto, la clase del destructor (Base2) se considera la clase más derivada, y esa es la razón por la cual el objeto no está relacionado con el tipo de destino (Base1*) de ninguna manera. Además, el tipo estático del operandothisesBase2* const, que claramente es un puntero a la propia clase del destructor. Por lo tanto, la regla sobre el comportamiento indefinido no se aplica. En resumen, tenemos un comportamiento bien definido.fuente
[class.cdtor]/6mencioné en la otra respuesta que dice lo mismo que cppref: "Si el operando de dynamic_cast se refiere al objeto en construcción o destrucción y el tipo estático del operando no es un puntero u objeto del constructor o propia clase de destructor o una de sus bases, el resultado de dynamic_cast en un comportamiento indefinido ".