¿es posible reinicializar un objeto de una clase utilizando su constructor?Llamar a un constructor para reinicializar el objeto
Respuesta
o menos. Dada una clase A:
A a;
...
a = A();
la última afirmación no es de inicialización, es la asignación, pero probablemente hace lo que quiere.
+1 Por supuesto, esto también requiere escribir un operador de asignación completo y correcto. –
@Greg Esto requiere TENER un operador de asignación correcto, no necesariamente ESCRIBIR uno: el valor predeterminado a menudo será perfectamente correcto. –
¿Causará esto una pérdida de recursos si 'a' se instanciara usando una palabra clave' new'? – davidhood2
No, los constructores solo se llaman cuando se crea el objeto por primera vez. Escribe un nuevo método para hacerlo en su lugar.
Editar
no voy a reconocer la colocación de nuevo, porque no quiero tener que conseguir un raptor mascota para el trabajo.
See this comic, pero pensar en el tema a la mano ...
Respuesta corta:
No. Si parte del comportamiento previsto de su objeto debe ser inicializado varias veces, entonces la mejor manera de implementar esto es a través de un método de inicialización accesible. El constructor de tu clase simplemente puede diferir a este método. esquina
class C1 {
public:
C1(int p1, int p2) {
Init(p1,p2);
}
void Init(int p1, int p2) { ... }
};
nitpicker:
¿Hay alguna manera increíblemente mal para llamar a un constructor en C++ después de un objeto se crea? Casi con certeza, esto es C++ después de todo. Pero es fundamentalmente malo y su comportamiento casi con seguridad no está definido por el estándar y debe evitarse.
Es posible, aunque es una muy mala idea. La razón por la cual es que sin llamar a los destructores en el objeto existente, va a perder recursos.
Con esa advertencia importante, si insiste en hacerlo, puede utilizar la ubicación nueva.
// Construct the class
CLASS cl(args);
// And reconstruct it...
new (&cl) CLASS(args);
Deberías obtener un -1 solo por sugerirle a alguien: P, pero un +1 para el truco - no lo sabía, entonces 0 en total –
Uno podría 'cl-> ~ CLASE();' antes de la colocación nueva, como dije en la respuesta de Jared. No estoy seguro si eso está definido, parece legal. – GManNickG
+1, única solución correcta. Nada malo, es la forma en que se hace. –
¿Literalmente? Sí, al usar la colocación nueva. Pero primero debes destruir el objeto previamente construido.
SomeClass object(1, 2, 3);
...
object.~SomeClass(); // destruct
new(&object) SomeClass(4, 5, 6); // reconstruct
...
// Final destruction will be done implicitly
Sin embargo, el valor de esto no va más allá de lo puramente teórico. No lo hagas en la práctica. Todo es feo más allá de la descripción.
¿Puede explicar por qué cree que esto es "feo más allá de la descripción"? Me parece que tiene un uso legítimo para evitar la duplicación de código y los errores que surgen al tener un método 'claro' separado de un constructor y un destructor –
este "feo" es que después de llamar al destructor en 'object', tiene una variable de pila no inicializada. Intentar hacer cualquier cosa con' object' después de este punto es inseguro. No hay ni siquiera una manera de tect que el objeto ha sido destruido más tarde. Pero una vez reconstruido, es válido de nuevo. Yo diría que siempre y cuando esas dos líneas estén consecutivas, esto es seguro. –
Honestamente, probablemente pondría esto en algún tipo de función de plantilla vardic o incluso solo en una macro, para dejar en claro lo que está sucediendo y para evitar que el código se inserte accidentalmente entre las dos declaraciones. – LivePastTheEnd
Puede que no sea lo que tiene en mente, pero como no mencionó para qué sirve, supongo que una respuesta sería que lo haría controlando el alcance y el flujo del programa.
Por ejemplo, no se escribiría un juego como este:
initialize player
code for level 1
...
reinitialize player
code for level 2
...
etc
En su lugar, habría esfuerzan para:
void play_level(level_number, level_data) {
Player player; //gets "re-initialized" at the beginning of each level using constructor
//code for level
}
void game() {
level_number = 1;
while (some_condition) {
play_level(level_number, level_data);
++level_number;
}
}
(esquema muy aproximado para transmitir la idea, no pretende ser compilable de forma remota.)
Sí, puedes hacer trampa y usar la ubicación nueva.
Nota: No aconsejo esto:
#include <new>
reInitAnA(A& value)
{
value.~A(); // destroy the old one first.
new (&value) A(); // Call the constructor
// uses placement new to construct the new object
// in the old values location.
}
¿Qué pasa si el nuevo falla? – Jagannath
En este caso, no puede fallar el nuevo (en términos de asignación de memoria) ya que no se asigna memoria. El constructor puede fallar y lanzar excepciones tal como cabría esperar. –
Posiblemente lo que quiere decir Jagannath es, ¿qué ocurre si se lanza una excepción y el objeto pasado como parámetro es, por ejemplo,? una variable automática que pertenece a la persona que llama, o un objeto asignado dinámicamente sostenido por un puntero inteligente. ¿Cuándo es válido llamar al destructor dos veces, cómo se puede escribir código para garantizar la validez, etc.? –
En lugar de destruirse y reinicializar según lo sugerido por algunas de las respuestas anteriores, es mejor que hacer una misión, como a continuación. El código a continuación es excepcionalmente seguro.
T& reinitialize(int x, int y)
{
T other(x, y);
Swap(other); // this can't throw.
return *this;
}
En C++ 11, se puede hacer esto:
#include <type_traits>
template <class T, typename... Args>
void Reconstruct(T& x, Args&&... args)
{
static_assert(!std::has_virtual_destructor<T>::value, "Unsafe");
x.~T();
new (&x) T(std::forward<Args>(args)...);
}
Esto le permite utilizar Reconstruct
pasan parámetros del constructor arbitrarias a cualquier objeto. Esto puede evitar tener que mantener un montón de métodos Clear
, y errores que pueden pasar desapercibidos si en algún momento el objeto cambia, y el método Clear
ya no coincide con el constructor.
Lo anterior funcionará bien en la mayoría de los contextos, pero falla horriblemente si la referencia es a una base dentro de un objeto derivado que tiene un destructor virtual. Por esta razón, la implementación anterior impide el uso con objetos que tienen un destructor virtual.
que suelo escribir lo siguiente en C moderna ++:
SomeClass a;
...
a = decltype(a)();
Puede ser no es la forma más eficaz, ya que construye de manera efectiva otro objeto del mismo tipo de a
y lo asigna a a
, pero funciona en la mayoría de los casos, no tiene que recordar el tipo de a
, y se adapta si el tipo cambia.
- 1. Llamar a un constructor para reinicializar variables no parece funcionar?
- 2. Llamar a un método en Constructor
- 3. Usando un delegado para llamar a un constructor
- 4. Utilizando C# reflexión para llamar a un constructor
- 5. Constructor o función init para un objeto
- 6. ¿Puede un constructor llamar a otro constructor en C++?
- 7. Llamar a un constructor parametrizado de XAML
- 8. Llamar a un método desde el constructor en Coffeescript
- 9. ¿Puedo llamar a un constructor de copia de forma explícita?
- 10. serie de parámetros a constructor de objeto
- 11. Reinicializar Git Repo
- 12. ¿Cómo forzar a moq a llamar al constructor?
- 13. Llamar a un método reemplazado de un constructor
- 14. Inyección de constructor: ¿a dónde llamar?
- 15. Definición de un objeto sin llamar a su constructor en C++
- 16. ¿Cuándo necesita llamar explícitamente a un constructor de superclase?
- 17. Llamar a las funciones miembro desde un constructor
- 18. llamar al constructor de otro constructor
- 19. ¿Por qué un puntero inteligente no puede llamar a new() para mí en su constructor?
- 20. Por qué llamar explícitamente a un constructor en C++
- 21. No se puede llamar a un constructor sobrecargado en Scala
- 22. Llamar a un constructor desde argumentos variables con PHP
- 23. ¿Cómo llamar a un constructor diferente condicionalmente en Java?
- 24. ¿Por qué llamar a super() en un constructor?
- 25. C# llamar a un constructor del cuerpo de otro
- 26. Uso heredado en el constructor "Crear" de un objeto TObject
- 27. Javascript: Llamar a métodos de objeto dentro de ese objeto
- 28. Debería usar un nuevo tipo() o simplemente un tipo() para llamar a un constructor
- 29. ¿Cómo llamar a Html.Display para un objeto personalizado, no a todo el Modelo?
- 30. llamar al constructor de un tipo genérico
¿Qué quiere decir exactamente con reiniciar? – David
Dando a las variables los mismos valores cuando se crearon por primera vez. – cpx
La solución de Neil es "lo mejor", aunque su diseño necesita reparación. – GManNickG