Ответ 1
Сорт. Учитывая класс A:
A a;
...
a = A();
последнее утверждение не является инициализацией, это назначение, но оно, вероятно, делает то, что вы хотите.
Можно ли повторно инициализировать объект класса с помощью его конструктора?
Сорт. Учитывая класс A:
A a;
...
a = A();
последнее утверждение не является инициализацией, это назначение, но оно, вероятно, делает то, что вы хотите.
Буквально? Да, используя новое место размещения. Но сначала вы должны уничтожить ранее построенный объект.
SomeClass object(1, 2, 3);
...
object.~SomeClass(); // destruct
new(&object) SomeClass(4, 5, 6); // reconstruct
...
// Final destruction will be done implicitly
Значение этого не выходит за рамки чисто теоретического. Не делайте этого на практике. Все это некрасиво выходит за рамки описания.
Возможно, хотя это очень плохая идея. Причина в том, что без вызова деструкторов на существующий объект вы собираетесь утечка ресурсов.
С этим основным предостережением, если вы настаиваете на этом, вы можете использовать новое размещение.
// Construct the class
CLASS cl(args);
// And reconstruct it...
new (&cl) CLASS(args);
Нет, конструкторы вызываются только при первом создании объекта. Вместо этого напишите новый метод.
Edit
Я не буду признавать размещение новым, потому что я не хочу, чтобы у меня был любитель-хищник.
Посмотрите этот комикс, но подумайте об этой теме...
Короткий ответ:
Нет. Если часть вашего целевого поведения объекта должна быть инициализирована несколько раз, тогда лучший способ реализовать это - доступный метод инициализации. Конструктор вашего класса может просто отложить этот метод.
class C1 {
public:
C1(int p1, int p2) {
Init(p1,p2);
}
void Init(int p1, int p2) { ... }
};
Угол ниппеля:
Есть ли какой-то невероятно злой способ вызвать конструктор в С++ после создания объекта? Почти наверняка, это С++. Но это в корне зло, и это поведение почти наверняка не определено стандартом, и его следует избегать.
В С++ 11 вы можете сделать это:
#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)...);
}
Это позволяет использовать Reconstruct
передачу произвольных параметров конструктора любому объекту. Это может избежать необходимости поддерживать кучу методов Clear
и ошибок, которые могут легко остаться незамеченными, если в какой-то момент объект изменится, а метод Clear
больше не соответствует конструктору.
Вышеприведенное будет работать отлично в большинстве контекстов, но неудачно, если ссылка связана с базой внутри производного объекта, который имеет виртуальный деструктор. По этой причине описанная выше реализация предотвращает использование объектов, имеющих виртуальный деструктор.
Да, вы можете обмануть и использовать новое место. Примечание: я не советую:
#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.
}
Я обычно пишу следующее в современном С++:
SomeClass a;
...
a = decltype(a)();
Это может быть не самый эффективный способ, поскольку он эффективно создает другой объект того же типа a
и присваивает его a
, но он работает в большинстве случаев, вам не нужно запоминать тип от a
, и он адаптируется, если тип изменяется.
Может быть, это не то, что вы имеете в виду, но поскольку вы не указали, для чего это важно, я полагаю, что один ответ будет заключаться в том, что вы сделаете это, контролируя объем и поток программ.
Например, вы не будете писать такую игру:
initialize player
code for level 1
...
reinitialize player
code for level 2
...
etc
Вместо этого вы бы стремились:
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;
}
}
(Очень грубая схема, чтобы передать идею, а не быть удаленно компилируемой.)
Вместо того, чтобы разрушать и повторять инициализацию, как предложено некоторыми из вышеперечисленных ответов, лучше выполнить задание, как показано ниже. Код ниже является безопасным для исключений.
T& reinitialize(int x, int y)
{
T other(x, y);
Swap(other); // this can't throw.
return *this;
}
В то время как большинство ответов переинициализируют объект в два этапа; во-первых, создание исходного объекта, а затем создание другого объекта и замена его на первый с использованием placement new
; этот ответ охватывает случай, когда вы сначала создаете указатель на пустой объект, а затем выделяете и конструируете его:
class c *c_instance; // Pointer to class c
c_instance = new c(arg1, ..., argn) // Allocate memory & call the proper constructor
// Use the instance e.g. c->data
delete c_instance; // Deallocate memory & call the destructor