tutorialspoint template online new management generic compiler c++ interface terminology pure-virtual

template - tutorialspoint c++



¿Al poner un "destructor virtual dentro de una interfaz", por definición, ya no es una interfaz? (4)

Así que aquí está la caja en la que estoy. Quiero entender por qué es importante tener un "destructor virtual dentro de su clase de interfaz". Verás por qué esas cosas están entre comillas si puedes colgar hasta el final ... También quiero que todo el vocabulario sea absolutamente correcto. Aquí es donde estoy con el proceso hasta ahora:

  1. A veces tienes clases base, a veces tienes clases derivadas que heredan de las clases base.

  2. Si tiene un puntero base que se encuentra apuntando a un objeto derivado, y además desea que una llamada de función miembro realizada desde ese puntero base apuntando a un objeto derivado se comporte como si realmente se hubiera llamado a partir del objeto derivado, entonces la función miembro a la que llama debería declararse virtual en la clase base.

  3. Una interfaz es cualquier clase con solo funciones virtuales puras. Si deriva una nueva clase de esta clase de interfaz e implementa todas las funciones virtuales puras, finalmente puede crear una instancia de la clase derivada.

  4. Nunca puede tener una instancia de una clase de interfaz, PERO puede tener una instancia de una clase de puntero a interfaz.

  5. En el caso de que tenga una clase de puntero a interfaz que realmente apunte a un objeto de la clase derivada (en realidad, supongo que siempre tendría que hacerlo si # 4 es correcto), y si decide eliminar ese objeto a través de su puntero, entonces si no tiene un "destructor virtual dentro de su clase de interfaz", su intención de destruir el objeto derivado solo se ejecutará como una llamada para destruir el objeto base (es decir, la clase de interfaz) y ya que no hay destructor virtual, las cosas nunca llegarán al punto donde realmente se llama al destructor para el objeto derivado, lo que provoca pérdidas de memoria.

Uf. Está bien, si eso suena bien, en mi pregunta. ¿Es suficiente declarar un destructor virtual dentro de su interfaz de esta manera?

virtual ~iFace();

Eso me parece mal ... así que, ¿qué pasa si haces que el destructor sea tan virtual como este?

virtual ~iFace() = 0;

Ya que son solo declaraciones, ¿alguno de estos cuenta por ser un "destructor virtual dentro de su clase de interfaz"? ¿Puedes incluso tener un destructor declarado pero sin definir? Solo si es puramente virtual supongo ...

De todos modos, volviendo a la pregunta del título ... Realmente voy tan rápido como puedo ... Aquí está la oportunidad de dinero ... Si su "destructor virtual dentro de su clase de interfaz" requiere al menos una definición vacía como esta :

virtual ~iFace() {};

Entonces esa función miembro no es puramente virtual (no puede ser porque le dio una definición) y, por lo tanto, su clase ya no es una interfaz (no solo contiene funciones miembro virtuales puras).

Esto implicaría que si define un destructor virtual para su interfaz, entonces ya no tendrá una interfaz (sino solo una clase base abstracta). ¿Es esto solo un abuso del lenguaje? ¿Entiendo lo que está pasando?

Nota: Todo esto vino de preguntarme "¿Qué es una interfaz?" y luego leer las respuestas de esta pregunta: ¿Cómo declara una interfaz en C ++?

Espero que no haya sido un paseo demasiado largo para un viaje muy corto, pero estoy decidido a entender completamente estos conceptos y su vocabulario asociado.


"Una interfaz es cualquier clase con funciones virtuales puras"

- El concepto en C ++ se llama clase abstracta . Una clase abstracta es una clase con al menos una función virtual pura. Sin embargo, no requiere que todas sus funciones miembro sean puramente virtuales. No puedes instanciar ninguna clase abstracta.

"Esto implicaría que si define un destructor virtual para su interfaz, entonces ya no tendrá una interfaz (sino solo una clase base abstracta). ¿Esto es solo un abuso de lenguaje? ¿Entiendo lo que está pasando?"

- Por el contrario, debe proporcionar una definición para el destructor, incluso si es puramente virtual, ya que los destructores siempre son llamados de forma descendente en la jerarquía de herencia.

Estándar 12.4:

Un destructor puede ser declarado virtual (10.3) o puro virtual (10.4); Si se crea algún objeto de esa clase o cualquier clase derivada en el programa, se definirá el destructor.

Ejemplo:

class A { public: // this is stil a pure virtual function // when there is a definition virtual ~A() = 0; }; class B: public A {}; int main() { // fail to link due to missing definition of A::~A() B b; }


  1. DE ACUERDO.
  2. DE ACUERDO; si la función miembro no se declara virtual en la clase base, se llama a la de la clase base; si la función miembro no está definida ni declarada virtual pura en la clase base, obtendrá un error.
  3. En C ++ no tiene interfaces como en Java y C #; las clases base abstractas en C ++ combinan interfaces y clases abstractas, ya que están presentes en los dos últimos idiomas. Una clase de C ++ es abstracta si tiene al menos una función miembro virtual pura.
  4. Reemplace la interfaz con la clase abstracta .
  5. Formalmente no puede hacer suposiciones sobre lo que sucede si elimina una clase derivada de un puntero a una clase base si el destructor de la clase base no se declara virtual.

Dado todo esto, en general, su clase base abstracta ya tendrá alguna función miembro virtual pura que garantiza que no será posible instanciarla, por lo que la forma habitual de hacer las cosas es definir un destructor virtual en línea que no hace nada.


C ++ no tiene una entidad de interfaz nativa. Las interfaces se implementan como clases regulares.

Lo que hace que una clase sea una interfaz en C ++ no es, por lo tanto, algo que tenga un acuerdo universal. Personalmente, considero que una clase es una interfaz si no tiene miembros de datos, ningún constructor declarado por el usuario y todas sus funciones son virtuales, con la posible excepción de su destructor, y todas sus clases base, si las hay, también son interfaces Si una clase no se ajusta a todas estas propiedades, podría referirme a ella como una interfaz "gruesa" (¡en general no es un cumplido!).

Si desea eliminar las clases polimórficas asignadas dinámicamente a través de un puntero a una clase base (como una clase de "interfaz"), el destructor de la clase base debe declararse virtual . Esto significa que debe ser un destructor declarado por el usuario y no un destructor declarado implícitamente que no sería virtual .

Una vez que declara un destructor explícitamente, debe proporcionar una implementación para él. (Siempre se utilizará un destructor de clase base cuando destruya una instancia de cualquier clase derivada de él, ya sea que el destructor de clase base se declare virtual, virtual o no virtual). Esto es simplemente un detalle de implementación en lenguaje C ++. No significa que su clase base sea menos que una "interfaz"; si tiene una clase de interfaz, es muy probable que la implementación del destructor esté vacía en cualquier caso; no tiene miembros ni clases base con miembros de los que preocuparse

Si su interfaz tiene al menos algunas funciones virtuales puras, entonces no hay un mérito real para marcar el destructor como puro, su clase de interfaz ya es una clase abstracta. Los destructores de clase derivados no anulan técnicamente los destructores de clase base, por lo que no es necesario que las clases derivadas proporcionen destructores declarados por el usuario ni nada de eso.

Declarar un destructor como un virtual puro también le roba la capacidad de proporcionar la definición del destructor en línea en la definición de clase, aunque este es un detalle menor.


¿Por qué Abstract class destructor debería ser virtual y tener una definición?

Llamar a delete en un puntero de clase base polimórfica que apunta a un objeto de clase Derivado y la clase Base que no tiene un destructor virtual provoca un comportamiento indefinido .

Por lo tanto, es necesario declarar el destructor de la clase Base polimórfica como virtual . Una vez que declare su destructor explícitamente virtual, debe proporcionar una definición para él. Esto se debe a que el compilador de manera predeterminada genera (define) un destructor para cada clase, pero si declara explícitamente el destructor, el compilador no lo hace y lo deja para que proporcione una definición para su propio destructor. Tiene sentido porque el compilador ve la declaración explícita como una indicación de que desea realizar algunas operaciones no triviales (incluso si no necesita hacerlo) en el destructor y le brinda la oportunidad de hacerlo al forzarlo a dar la definición.

Mito 1:
Hay algo llamado Interface en C ++.

NO
C ++ como lenguaje no proporciona una Interface lo que se refiere como Interface se llama una Abstract class en C ++. Abstract Classes se utilizan para simular el comportamiento de la Interface en C ++.

¿Que es una clase abstracta?
Por definición, una clase abstracta debe tener al menos una función virtual pura.

Mito 2:
Todas las funciones dentro de la clase abstracta deben ser puramente virtuales.

NO
Abstract classes no requieren que todas las funciones dentro de ellas sean puramente virtuales. No se puede crear un objeto de un Resumen si tiene al menos una función virtual pura. Aunque, como mencionaste correctamente, puedes crear punteros a él.

Mito 3:
Las funciones virtuales puras no pueden tener una definición.

NO
Es perfectamente válido que las funciones virtuales puras tengan una definición.

¿Por qué necesitaría una Pure virtual function con definición?
El código habla más fuerte que las palabras, así que aquí hay un ejemplo simple:
Advertencia: Código no compilado solo para demostración

class IMyInterface { int i; int j; public: virtual void SetMembers(int ii, int jj)=0; }; /*The pure virtual function cannot be inline in the class definition*/ /*So this has to be here*/ void IMyInterface::SetMembers(int ii, int jj) { i = ii; j = jj; } class Myclass: public IMyInterface { int k; int l; public: virtual void SetMembers(int ll, int m, int a, int b) { k = ll; l = m; IMyInterface::SetMembers(a,b); } }; int main() { MyClass obj; obj.SetMembers(10,20,30,40); return 0; }