una resueltos que programacion orientada objetos herencia ejercicios ejemplos codigo clases clase c++ c++11 constructor virtual-functions dynamictype

resueltos - programacion orientada a objetos c++ ejemplos



¿Es una mala práctica llamar a una función virtual desde el constructor de una clase que está marcada como final? (3)

Esto todavía se consideraría una mala práctica, ya que este tipo de esto casi siempre indica un mal diseño. Tendría que comentar el código del código para explicar por qué esto funciona en este caso.

El comentario de TC anterior refuerza una de las razones por las que esto se considera una mala práctica.

¿Qué sucede si, un año después, decides que el derivado no debería ser definitivo después de todo?

Dicho esto, en el ejemplo anterior, el patrón funcionará sin problemas. Esto se debe a que el constructor del tipo más derivado es el que llama a la función virtual. Este problema se manifiesta cuando el constructor de una clase base llama a una función virtual que se resuelve en la implementación de un subtipo. En C ++, una función de este tipo no se llamará, porque durante la construcción de la clase base, tales llamadas nunca irán a una clase más derivada que la del constructor o destructor que se está ejecutando actualmente. En esencia, terminas con un comportamiento que no esperabas.

Editar:

Todas las implementaciones de C ++ (correctas / no defectuosas) deben llamar a la versión de la función definida en el nivel de la jerarquía en el constructor actual y no más.

El C ++ FAQ Lite cubre esto en la sección 23.7 con bastante buen detalle.

Scott Meyers también se ocupa de la cuestión general de llamar a funciones virtuales de constructores y destructores en Effective C ++ Item 9

Normalmente, llamar a las funciones virtuales de los constructores se considera una mala práctica, ya que las funciones anuladas en los subobjetos no se llamarán porque los objetos aún no se han construido.

Pero, considere las siguientes clases:

class base { public: base() {} ~base() {} private: virtual void startFSM() = 0; }; class derived final : public base , public fsm_action_interface { public: derived() : base{} , theFSM_{} { startFSM(); } /// FSM interface actions private: virtual void startFSM() { theFSM_.start(); } private: SomeFSMType theFSM_; }

En este caso, la clase derived se marca como final por lo que no pueden existir otros subobjetos. Ergo la llamada virtual se resolverá correctamente (al tipo más derivado).

¿Todavía se considera una mala práctica?


Puede funcionar, pero ¿por qué startFSM() necesita ser virtual ? En ningún caso, realmente desea llamar a algo que no sea derived::startFSM() , ¿por qué tiene un enlace dinámico? Si desea que llame a lo mismo que un método enlazado dinámicamente, realice otra función no virtual llamada startFSM_impl() y que el constructor y startFSM() llamen en su lugar.

Siempre prefiera lo no virtual a lo virtual si puede evitarlo.


Respecto a

" Normalmente, llamar a las funciones virtuales de los constructores se considera una mala práctica, ya que las funciones anuladas en los subobjetos no se llamarán porque los objetos aún no se han construido.

Ese no es el caso. Entre los programadores competentes de C ++, normalmente no se considera una mala práctica llamar funciones virtuales (excepto las virtuales) de los constructores, porque C ++ está diseñado para manejar eso bien. A diferencia de lenguajes como Java y C #, donde podría resultar en una llamada a un método en un subobjeto de clase derivado aún sin inicializar.

Tenga en cuenta que el ajuste dinámico del tipo dinámico tiene un costo de tiempo de ejecución.

En un lenguaje orientado hacia la máxima eficiencia, con "no pagas por lo que no usas" como principio guía principal, eso significa que es una característica importante y muy intencional, no una elección arbitraria. Está allí por un solo propósito. Es decir, para apoyar esas llamadas.

Respecto a

En este caso, la clase derivada se marca como final, por lo que no pueden existir más subobjetos. Ergo la llamada virtual se resolverá correctamente (al tipo más derivado).

El estándar C ++ garantiza que en el momento de la ejecución de la construcción para una clase T , el tipo dinámico es T.

Por lo tanto, no hubo ningún problema sobre la resolución de un tipo incorrecto, en primer lugar.

Respecto a

¿Todavía se considera una mala práctica?

De hecho, es una mala práctica declarar una función miembro virtual en una clase final , porque eso no tiene sentido. El "alambique" no es muy significativo. ya sea.

Lo siento, no vi que la función miembro virtual se haya heredado como tal.

La mejor práctica para marcar una función miembro como anulación o implementación de virtual puro, es usar la override la palabra clave, no marcarla como virtual .

Así:

void startFSM() override { theFSM_.start(); }

Esto asegura un error de compilación si no es una anulación / implementación.