Existe un concepto erróneo: la herencia, fuera del concepto de POO puro, que C++ no lo es, no es más que una "composición con un miembro sin nombre, con capacidad de decaimiento".
La ausencia de funciones virtuales (y el destructor no es especial, en este sentido) hace que su objeto no sea polimórfico, pero si lo que está haciendo es simplemente "reutilizarlo y exponer la interfaz nativa", la herencia hace exactamente lo que preguntó.
Los destructores no necesitan ser llamados explícitamente entre sí, ya que su llamada siempre está encadenada por especificación.
#include <iostream>
unsing namespace std;
class A
{
public:
A() { cout << "A::A()" << endl; }
~A() { cout << "A::~A()" << endl; }
void hello() { cout << "A::hello()" << endl; }
};
class B: public A
{
public:
B() { cout << "B::B()" << endl; }
~B() { cout << "B::~B()" << endl; }
void hello() { cout << "B::hello()" << endl; }
};
int main()
{
B b;
b.hello();
return 0;
}
es la salida
A::A()
B::B()
B::hello()
B::~B()
A::~A()
de tomar una incrustado en B con
class B
{
public:
A a;
B() { cout << "B::B()" << endl; }
~B() { cout << "B::~B()" << endl; }
void hello() { cout << "B::hello()" << endl; }
};
que dará salida a exactamente la misma.
El "No deriva si el destructor no es virtual" no es una consecuencia obligatoria de C++, sino simplemente una regla no escrita comúnmente aceptada (no hay nada en la especificación: aparte una UB llamando a eliminar en una base) que surge antes de C++ 99, cuando OOP por herencia dinámica y funciones virtuales era el único paradigma de programación compatible con C++.
Por supuesto, muchos programadores de todo el mundo hicieron sus huesos con ese tipo de escuela (el mismo que enseñan iostreams como primitivas, a continuación, se mueve a la matriz y punteros, y en la última lección que el maestro dice "oh. .. tehre es también el STL que tiene vector, cadena y otras características avanzadas ") y hoy, incluso si C++ se convirtió en multiparadigm, aún insiste con esta regla OOP pura.
En mi muestra A :: ~ A() no es virtual exactamente como A :: hello. Qué significa eso?
simple: por la misma razón llamando A::hello
no dará lugar a llamar B::hello
, llamando A::~A()
(por delete) no dará lugar a B::~B()
. Si puede aceptar -en su estilo de programación- la primera afirmación, no hay ninguna razón por la que no pueda aceptar el segundo. En mi muestra no hay A* p = new B
que recibirá delete p
ya que A :: ~ A no es virtual y Sé lo que significa.
Exactamente esa misma razón que no hará, utilizando el segundo ejemplo para B, A* p = &((new B)->a);
con un , aunque este segundo caso, perfectamente dual con el primero, no parece interesante a nadie sin razones aparentes.
El único problema es el "mantenimiento", en el sentido de que -si un programador OOP ve el código yopur- lo rechazará, no porque sea incorrecto en sí mismo, sino porque se lo han indicado.
De hecho, el "no deriva si el destructor no es virtual" es porque la mayoría de los programadores creen que hay demasiados programadores que no saben que no pueden llamar eliminar en un puntero a una base. (Lo siento si esto no es de buena educación, pero después de 30 años de experiencia en programación no puede ver ninguna otra razón!)
Pero su pregunta es diferente:
Calling B :: ~ B() (por eliminación o por alcance del alcance) siempre dará como resultado A :: ~ A() ya que A (ya sea incrustado o heredado) es en cualquier caso parte de B.
Tras los comentarios Luchian: el comportamiento Indefinido aludido por encima de una de sus comentarios se relaciona con una deleción en un an-object's base puntero a sin destructor virtual.
Según la escuela OOP, esto da como resultado la regla "no se deriva si no existe un destructor virtual".
Lo que estoy señalando, aquí, es que las razones de esa escuela dependen del hecho de que cada objeto orientado OOP tiene que ser polimórfico y todo es polimórfico debe ser direccionable por puntero a una base, para permitir la sustitución de objetos . Al hacer esas afirmaciones, esa escuela intenta deliberadamente anular la intersección entre derivado y no reemplazable, de modo que un programa OOP puro no experimentará ese UB.
Mi posición, simplemente, admite que C++ no es solo OOP, y no todos los objetos de C++ TENGO QUE ORIENTARSE de manera predeterminada, y admitir OOP no siempre es una necesidad necesaria, también admite que la herencia de C++ no siempre es necesariamente sirviendo a la sustitución OOP.
std :: map NO es polimórfico, por lo que NO es reemplazable. MyMap es lo mismo: NO polimórfico y NO reemplazable.
Simplemente tiene que volver a usar std :: map y exponer la misma interfaz std :: map. Y la herencia es solo la forma de evitar una larga repetición de funciones reescritas que solo llama a las reutilizadas.
MyMap no tendrá controlador virtual, ya que std :: map no tiene uno. Y esto, para mí, es suficiente para decirle a un programador de C++ que estos no son objetos polimórficos y que no deben usarse uno en lugar del otro.
Tengo que admitir que esta posición no la comparten actualmente la mayoría de los expertos en C++. Pero creo (mi única opinión personal) esto es solo debido a su historia, que se relacionan con OOP como un dogma para servir, no debido a una necesidad de C++. Para mí, C++ no es un lenguaje POO puro y no siempre debe seguir necesariamente el paradigma de POO, en un contexto donde no se sigue o no se requiere POO.
+1 Siempre favorece la composición en lugar de la herencia. Aún así, desearía que hubiera alguna manera de reducir todo el código repetitivo necesario para envolver. – daramarak
@daramarak: yo también, si algo como 'using attribute.insert;' pudiera funcionar! Por otro lado, es bastante raro que realmente necesites todos los métodos, y envolverlo te da la oportunidad de dar un nombre significativo y tomar tipos de nivel superior :) –
@daramarak: * Todavía deseo que haya alguna forma de reducir todo el código repetitivo necesario para envolver *: sí, hay: herencia. Pero los programadores están convencidos de que no deberían usarlo ... porque siempre tienden a interpretarlo como "es una". Pero eso no es un requisito, solo una convención pública. –