Pregunta

¿Hay una razón por la std::type_info se especifica a ser polimórficos? El destructor se especifica a ser virtual (y hay un comentario en el sentido de "por lo que es polimórfico" en el diseño y evolución de C ++). Realmente no puedo ver una razón de peso por qué. No tengo ningún caso de uso específico, me estaba preguntando si alguna vez hubo una razón o historia detrás de él.


Aquí hay algunas ideas que yo he llegado con y rechazado:

  1. Es un punto de extensibilidad - implementaciones podrían definir subclases, y programas podrían luego tratar de dynamic_cast un std::type_info a otro, tipo derivado definido por la implementación. Esta es posiblemente la razón, pero parece que es igual de fácil para implementaciones para añadir un miembro de aplicación definidos, lo que podría ser virtual. Los programas que desean prueba para estas extensiones serían necesariamente todos modos no portátil.
  2. Es para asegurarse de que los tipos derivados se destruyen correctamente cuando deleteing un puntero base. Pero no hay tipos estándar derivada, los usuarios no pueden definir tipos de derivados útiles, porque type_info tiene constructores públicos estándar, y así deleteing un puntero type_info no es legal y portátil. Y los tipos derivados no son útiles porque no pueden ser construidos - el único uso que sé para tales tipos derivados no construibles es en la implementación de cosas como el rasgo de tipo is_polymorphic
  3. .
  4. deja abierta la posibilidad de metaclases con tipos personalizados - cada class A polimórfica real sería conseguir un A__type_info derivada "metaclase", que se deriva de type_info. Quizás tales clases derivadas pueden exponer a los miembros que new A llamada con diversos argumentos del constructor en una forma de tipo seguro, y cosas por el estilo. Pero haciéndose polimórfica type_info realidad hace que tal idea básicamente imposible de implementar, ya que tendría que tener metaclases para sus metaclases, hasta el infinito, que es un problema si todos los objetos type_info tienen una duración de almacenamiento estático. Tal vez Salvo esto es la razón de lo que es polimórfica.
  5. Hay alguna utilidad para aplicar características de RTTI (excepto dynamic_cast) a std::type_info sí mismo, o pensó que alguien que era lindo, o embarazoso si type_info no era polimórfica. Pero dado que no hay ningún tipo derivado estándar, y no hay otras clases en la jerarquía estándar que se podría intentar razonablemente cruzada fundido a, la cuestión es: ¿qué? ¿Hay un uso para expresiones tales como typeid(std::type_info) == typeid(typeid(A))?
  6. Se debe a que los ejecutores crearán su propio tipo derivado privada (como creo que hace GCC). Pero, ¿por qué molestarse especificándolo? Incluso si el destructor no se especificó como virtual y un ejecutor decidió que debería ser, sin duda que la aplicación pueda declarar virtual, porque no cambia el conjunto de operaciones permitidas en type_info, por lo que un programa portátil no sería capaz a notar la diferencia.
  7. Es algo que ver con los compiladores parcialmente compatibles con coexistente ABIs, posiblemente como resultado de la vinculación dinámica. Tal vez los ejecutores podían reconocer su propia subclase type_info (en contraposición a una proveniente de otro proveedor) de una manera portátil, si type_info se garantiza que sea virtual.

La última es la más plausible para mí en este momento, pero es bastante débil.

¿Fue útil?

Solución

Asumo que está ahí para la comodidad de los ejecutores. Se les permite definir clases type_info extendidos, y eliminarlos a través de punteros a type_info al salir del programa, sin tener que construir en la magia especial compilador para llamar al destructor correcta, o no pasar por el aro.

  

duda de que la aplicación podría   os lo virtual, porque no lo hace   cambiar el conjunto de operaciones permitidas   en type_info, por lo que un programa portátil   no sería capaz de decir la   diferencia.

No creo que eso sea cierto. Considere lo siguiente:

#include <typeinfo>

struct A {
    int x;
};

struct B {
    int x;
};

int main() {
    const A *a1 = dynamic_cast<const A*>(&typeid(int));
    B b;
    const A *a2 = dynamic_cast<const A*>(&b);
}

Ya se trate de razonable o no, se permite que el primer grupo dinámico (y evalúa a un puntero nulo), mientras que no se permite que el segundo modelo dinámico. Por lo tanto, si type_info se define en la norma para que el destructor por defecto no virtual, sino una aplicación añade un destructor virtual, a continuación, un programa portátil podría decir la diferencia [*].

Parece más sencillo para mí para poner el destructor virtual en la norma, que a cualquiera:

a) poner una nota en la norma de que, a pesar de la definición de clase implica que type_info no tiene funciones virtuales, se les permite tener un destructor virtual.

b) determinar el conjunto de programas que se puede distinguir si type_info es polimórfico o no, y prohibir a todos. Puede que no sean programas muy útiles o productivas, no sé, pero para su prohibición que tiene que llegar a algún lenguaje estándar que describe la excepción específica que está haciendo a las reglas normales.

Por lo tanto creo que la norma tiene que exigir ya sea el destructor virtual, o prohibirlo. Por lo que es opcional es demasiado complejo (o tal vez debería decir, creo que sería juzgado innecesariamente compleja. Complejidad nunca dejó el comité de estándares en las áreas donde se consideró que vale la pena ...)

Si que fue prohibida, sin embargo, a continuación, una aplicación podría:

  • añadir un destructor virtual en cierta clase derivada de type_info
  • derivar toda su typeinfo objetos de que class
  • usar que internamente como la clase base polimórfica por todo

que resolvería la situación que he descrito en la parte superior del poste, y el tipo estático de una expresión typeid seguiría siendo const std::type_info, por lo que sería difícil para implementaciones para definir extensiones donde los programas pueden dynamic_cast a varios objetivos para ver qué tipo de objeto type_info que tienen en un caso particular. Tal vez el estándar de espera para permitir que, a pesar de una implementación siempre podía ofrecer una variante de typeid con un tipo estático diferente, o garantía de que un static_cast a una determinada clase de extensión va a funcionar, y luego dejar que el programa dynamic_cast desde allí.

En resumen, por lo que yo sé que el destructor virtual es potencialmente útil a los ejecutores, y la eliminación no gana nadie más que cualquier cosa que no sería pasar el tiempo preguntándose por qué está allí; -)

[*] En realidad, no he demostrado que. He demostrado que un programa ilegal sería, todo ser lo demás igual, compilación. Sin embargo, una aplicación podría tal vez resolver esto para que no todos son iguales, y que no se compilará. is_polymorphic de impulso no es portátil, lo que si bien es posible que un programa de prueba de que una clase es polimórfica, que debería ser, puede no haber camino para un programa conforme a la prueba de que una clase no es polimórfica, que no debe ser. Sin embargo, creo que incluso si es imposible, lo que demuestra que, con el fin de eliminar una línea de la norma, es bastante mucho esfuerzo.

Otros consejos

El C ++ estándar dice que typeid devuelve un objeto de tipo type_info, OR AN definido por la implementación subclase de los mismos. Así que ... supongo que esto es más o menos la respuesta. Así que no veo por qué se rechaza sus puntos 1 y 2.

El párrafo 5.2.8 Cláusula 1 de la corriente de C ++ estándar lee:

  

El resultado de una expresión typeid es una   lValue de const tipo estático   std :: type_info (18.5.1) y dinámico   tipo const std :: type_info o const   nombre donde nombre es una   clase de implementación definidos deriva   de std :: type_info que conserva   el comportamiento descrito en 18.5.1.61)   El tiempo de vida del objeto a que se refiere   por el lvalue se extiende hasta el final de   el programa. Sea o no el   destructor se invoca para la type_info   objeto al final del programa es   sin especificar.

Lo que a su vez significa que uno puede escribir el siguiente código es legal y fino: const type_info& x = typeid(expr); que puede requerir que type_info ser polimórficos

Sobre el más simple id "global" que puede tener en C ++ es un nombre de clase, y typeinfo proporciona una manera de comparar tales Identificación de la igualdad. Pero el diseño es tan torpe y limitado que este caso es necesario typeinfo envoltura de alguna clase de contenedor, por ejemplo, para ser capaz de poner los casos en colecciones. Andrei Alexandrescu hizo que en su "Modern C ++ Diseño" y creo que ese envoltorio typeinfo es parte de la biblioteca Loki; es probable que haya uno también en Boost; y es bastante fácil de rodar su propia, por ejemplo, ver mi propio envoltorio .

Pero incluso para una envoltura tales que no hay, en general, cualquier necesidad de un destructor virtual en typeinfo.

La pregunta, por tanto, no es tanto "eh, ¿por qué hay un destructor virtual", sino más bien, como yo lo veo, "eh, ¿por qué es el diseño de modo hacia atrás, torpe y no directamente utilizable"? Y me deja eso al proceso de normalización. Por ejemplo, iostreams no son precisamente ejemplos de diseño excelente, ya sea; no algo para emular.

  

3 / deja abierta la posibilidad de metaclases con tipos personalizados - cada class A polimórfica real sería conseguir una A__type_info derivada "metaclase", que deriva de type_info. Quizás tales clases derivadas pueden exponer a los miembros que new A llamada con diversos argumentos del constructor en una forma de tipo seguro, y cosas por el estilo. Pero haciéndose polimórfica type_info realidad hace que tal idea básicamente imposible de implementar, ya que tendría que tener metaclases para sus metaclases, hasta el infinito, que es un problema si todos los objetos type_info tienen una duración de almacenamiento estático. Tal vez Salvo esto es la razón de lo que es polimórfica.

Clever ...

De todos modos, no estoy de acuerdo con este razonamiento: dicha aplicación podría fácilmente descartar una meta clases de tipos derivados de type_info, incluyendo type_info

.
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top