c++ - Destructor de alias typedef
language-lawyer (2)
¿Por qué esto se aplica también al nombre del destructor?
Porque la norma dice:
[class.dtor]
En una llamada de destructor explícita, el destructor se especifica con un ~ seguido de un tipo-nombre o decltype-specifier que denota el tipo de clase del destructor. ...
Un alias typedef es un nombre de tipo que denota la misma clase que el nombre de tipo de la clase en sí.
La regla incluso tiene un ejemplo clarificador:
struct B { virtual ~B() { } }; struct D : B { ~D() { } }; D D_object; typedef B B_alias; B* B_ptr = &D_object; void f() { D_object.B::~B(); // calls B''s destructor B_ptr->~B(); // calls D''s destructor B_ptr->~B_alias(); // calls D''s destructor B_ptr->B_alias::~B(); // calls B''s destructor B_ptr->B_alias::~B_alias(); // calls B''s destructor }
Especificación adicional sobre la búsqueda de nombres, también con un ejemplo que se aplica a la pregunta:
[basic.lookup.qual]
Si un nombre de pseudo-destructor ([expr.pseudo]) contiene un especificador de nombre anidado, los nombres de tipo se buscan como tipos en el ámbito designado por el especificador de nombre anidado. Del mismo modo, en un id-calificado de la forma:
nombre-anidado-specifieropt nombre-clase :: ~ nombre-clase
el segundo nombre de clase se busca en el mismo ámbito que el primero. [Ejemplo:
struct C { typedef int I; }; typedef int I1, I2; extern int* p; extern int* q; p->C::I::~I(); // I is looked up in the scope of C q->I1::~I2(); // I2 is looked up in the scope of the postfix-expression struct A { ~A(); }; typedef A AB; int main() { AB* p; p->AB::~AB(); // explicitly calls the destructor for A }
- ejemplo final]
#include <iostream>
struct A { ~A(); };
A::~A() {
std::cout << "Destructor was called!" << std::endl;
}
typedef A AB;
int main() {
AB x;
x.AB::~AB(); // Why does this work?
x.AB::~A();
}
La salida del programa anterior es:
Destructor was called!
Destructor was called!
Destructor was called!
Asumo que las dos primeras líneas pertenecen a las llamadas del usuario destructor, mientras que la tercera línea se debe a que se llama al destructor al salir del alcance de la función main
.
Desde mi entendimiento, un typedef es un alias para un tipo. En este caso, AB
es un alias para A
¿Por qué esto se aplica también al nombre del destructor? Una referencia a la especificación del lenguaje es muy apreciada.
Edición: esto fue compilado usando Apple LLVM versión 9.1.0 (clang-902.0.39.1) en macOS High Sierra versión 10.13.3.
Porque cuando escribes ~AB()
no estás nombrando o llamando al destructor. Estás escribiendo ~
seguido del a nombre de la clase, y la llamada del destructor se aprovisiona automáticamente como resultado de la semántica especificada de escribir esos tokens uno al lado del otro.
Por lo general, esto es académico, pero aquí puedes ver por qué puede importar.
De manera similar, al escribir AB()
no estás "llamando a un constructor", a pesar de que parece una llamada de función y muchos de los recién llegados del idioma interpretan el código de esta manera. (Esto puede generar diversión y juegos al intentar llamar a un constructor de plantillas sin deducción de argumentos: sin poder nombrar al constructor, ¡no hay forma de proporcionar esos argumentos!)
De hecho, ¡ni el constructor ni el destructor técnicamente tienen nombre!
Estos matices hacen que C ++ sea divertido, ¿verdad?