que - polimorfismo puro c++
Cuándo es seguro llamar a una función virtual en un constructor (3)
¡Es absolutamente seguro llamar a cualquier función virtual no abstracta en el constructor o el destructor! Sin embargo, su comportamiento puede ser confuso ya que puede no hacer lo que se espera. Mientras se ejecuta el constructor de una clase, el tipo estático y dinámico del objeto es el tipo del constructor. Es decir, la función virtual nunca se enviará a la anulación de otra clase derivada. Aparte de eso, el despacho virtual realmente funciona: por ejemplo, cuando se llama a una función virtual a través de un puntero de clase base o la referencia se distribuye correctamente a la anulación en la clase que actualmente está siendo construida o destruida. Por ejemplo (probablemente plagado de errores ortográficos ya que actualmente no puedo este código):
#include <iostream>
struct A {
virtual ~A() {}
virtual void f() { std::cout << "A::f()/n"; }
void g() { this->f(); }
};
struct B: A {
B() { this->g(); } // this prints ''B::f()''
void f() { std::cout << "B::f()/n"; }
};
struct C: B {
void f() { std::cout << "C::f()/n"; } // not called from B::B()
};
int main() {
C c;
}
Es decir, puede invocar una función virtual, directa o indirectamente, en el constructor o un destructor de una clase si no desea que la función virtual se envíe a otra función derivada. Incluso puedes hacer esto: la función virtual es abstracta en la clase dada, siempre que esté definida. Sin embargo, tener una función abstracta indefinida que se envíe a provocará un error en tiempo de ejecución.
Tengo un código en el que realmente quiero llamar a un método virtual desde un constructor. Sé que esto se considera inseguro, y sé lo suficiente sobre la construcción de objetos para comprender también por qué . Tampoco estoy experimentando estos problemas . Actualmente mi código está funcionando y creo que debería estar bien, pero quiero asegurarme.
Esto es lo que estoy haciendo:
Tengo una jerarquía de clases y hay una función pública normal que simplemente reenvía a un método virtual privado, como de costumbre. Sin embargo, quiero llamar a este método público al construir mis objetos, porque está llenando todos los datos en el objeto. Estaré absolutamente seguro de que esta llamada virtual proviene de la clase hoja, porque el uso de este método virtual desde cualquier otra parte de la jerarquía de clases simplemente no tiene ningún sentido.
Entonces, en mi opinión, la creación del objeto debe finalizar una vez que realizo la llamada virtual y todo estará bien. ¿Todavía hay algo que podría salir mal? Supongo que tendré que marcar esta parte de la lógica con algunos comentarios importantes para explicar por qué esta lógica nunca debería moverse a ninguna de las clases base, aunque parezca que se podría mover. Pero aparte de la estupidez de otros programadores, estaría bien, ¿no?
Cuando se llama a un constructor, la clase se configura para que sea una instancia de esa clase, pero no la clase derivada. No puede llamar a una función virtual de una clase derivada desde un constructor base. Para cuando llegue al constructor de la clase más derivada, todas las funciones virtuales deben ser seguras para llamar.
Si desea asegurarse de que alguien no pueda realizar una llamada incorrecta, defina la función virtual en la clase base y haga que afirme y / o genere una excepción cuando se la llame.
La regla no es tanto que necesite estar en una clase de hoja como darse cuenta de que cuando hace una llamada de miembro de Foo::Foo(..)
, el objeto es exactamente un Foo
, incluso si está en camino a ser un Bar
(suponiendo que Foo
se deriva de Bar
y estás construyendo una instancia de Bar
). Eso es 100% confiable.
De lo contrario, el hecho de que el miembro sea virtual no es tan significativo. Hay otras trampas que suceden igual de bien con las funciones no virtuales: si tuviera que llamar a un método virtual o no virtual que supusiera que el objeto estaba completamente construido pero lo llamó dentro del constructor antes de que fuera el caso, también lo haría tener problemas. Estos son solo casos difíciles de precisar porque no solo debe funcionar la función que usted llama, sino que todas las funciones que llama deben estar bien.
No parece que tengas un problema, es solo uno de esos lugares propensos a que aparezcan errores.