Можете ли вы вызвать явный конструктор класса экземпляра объекта в C ++? - PullRequest
8 голосов
/ 24 ноября 2008

После создания экземпляра класса мы можем явно вызвать конструктор? Например

class A{
    A(int a)
    {
    }
}

A instance;

instance.A(2);

Можем ли мы сделать это?

Ответы [ 7 ]

14 голосов
/ 24 ноября 2008

Вы можете использовать новое размещение: http://en.wikipedia.org/wiki/Placement_new, что разрешает

new (&instance) A(2);

Однако из вашего примера вы дважды вызываете конструктор объекта, что является очень плохой практикой. Вместо этого я бы порекомендовал вам просто сделать

A instance(2);

Размещение нового обычно используется только тогда, когда вам нужно предварительно выделить память, например, в диспетчере нестандартной памяти.

10 голосов
/ 24 ноября 2008

Нет.

Создайте метод для набора и вызовите его из конструктора. Этот метод также будет доступен для дальнейшего использования.

class A{
    A(int a) { Set(a); }
    void Set(int a) { }
}

A instance;

instance.Set(2);

Возможно, вам также понадобится значение по умолчанию или конструктор по умолчанию.

4 голосов
/ 24 ноября 2008
нет

Нет

Calling instance.A() or A(1) is seens as casting  'function-style cast' : illegal as right side of '.' operator

Обычно, если функция / функциональность необходима в конструкторе, а также после создания объекта, он помещается в метод init () и используется в конструкторе и в другом месте.

пример:

 class A{
      A(int a)
       { 
        init(a);
       }

     void init(int a) { } 
     }

        A instance;

        instance.init(2);
3 голосов
/ 24 ноября 2008

Я почти уверен, что ты не сможешь этого сделать. В этом весь смысл, конструктор - это создание экземпляра класса.

Если конструктор вообще не вызывается или вызывается дважды - какие последствия это может иметь?

Конечно, вы могли бы извлечь из метода некоторую логику конструктора и вызвать этот метод как в конструкторе, так и после создания объекта.

1 голос
/ 24 ноября 2008

Кстати, это звучит как недостаток дизайна. После того, как объект сконструирован, больше не нужно его реконструировать. Такое повторное использование имен переменных делает код довольно сложным для понимания. По этой причине сделать конструкторские функции доступными через дополнительную функцию init или set часто неправильно (но иногда неизбежно).

Как сказал Майкл, здесь можно использовать новое размещение, но оно действительно предназначено для разных целей. Кроме того, перед созданием нового объекта в ячейке памяти вы должны явно уничтожить старый объект:

instance.~A();

Кроме того, placement new может оказать негативное влияние на вашу память, поскольку при перегрузках может ожидаться, что передаваемая память принадлежит куче! В заключение: не . делать. это.

РЕДАКТИРОВАТЬ Чтобы продемонстрировать, что вызов деструктора действительно необходим (для не POD), рассмотрим следующий пример кода:

#include <iostream>

struct A {
    A(int a) { std::cerr << "cons " << a << std::endl; }
    ~A() { std::cerr << "dest" << std::endl; }
};

int main() {
    A instance(2);
    new (&instance) A(3);
}

Как и ожидалось, программа выдаст следующий вывод:

cons 2
cons 3
dest

… что означает, что деструктор для первого объекта не вызван . То же самое касается любых ресурсов, которые A могли бы получить.

0 голосов
/ 18 марта 2009

Нет, вы не можете этого сделать. Единственный способ вызвать конструктор - это ключевое слово «new».

0 голосов
/ 24 ноября 2008

Подводя итог, можно указать три способа указания явного конструктора через

  1. Экземпляр (2); // делает экземпляр = 2; когда-нибудь работал?

  2. A * instance = new A (2); // я никогда не уверен в этом и против * здесь

  3. новый (& экземпляр) A (2);

и ароматы тех. Идея состоит в том, чтобы никогда не создавать объект, который не находится в надлежащем инициализированном состоянии, и конструкторы предназначены для обеспечения этого. (Это означает, что методы не должны проверять, был ли успешно вызван какой-либо метод .init (...).)

Мне кажется, что это более функциональный способ, особенно для классов, которые являются частью фреймворков и повторно используются в библиотеках. Если это то, что вас интересует, работайте над тем, чтобы все конструкторы, включая любой по умолчанию, доставляли полностью работающий экземпляр.

Исключительные случаи: Есть вещи, которые вы можете не иметь в операции конструктора, если они могут потерпеть неудачу, если только не целесообразно выбросить исключение из конструктора. А некоторым нравится иметь «пустые» экземпляры, которые распространяются с использованием последующих методов и даже подвергаются инициализации. Интересно изучить способы смягчения таких ситуаций и иметь надежные экземпляры, которые не имеют плохих состояний, от которых необходимо защищаться в реализациях методов и при использовании.

PS: В некоторых сложных случаях может быть полезно, чтобы инициализированный экземпляр (ссылка) был доставлен как результат функции или метода в «фабричном» классе, так что промежуточный экземпляр с недопустимой настройкой никогда не виден за пределами инкапсулирующего экземпляра или функции класса фабрики. Это дает нам,

+ 4. A * instance = MakeAnA (2);

+ 5. A * instance = InterestingClass.A (2);

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...