Детали синтаксиса конструктора C ++ - PullRequest
3 голосов
/ 16 октября 2011

Это почти повторяющийся вопрос, но я действительно не понял ответ на другой вопрос, поэтому я попробую еще раз:

Я изучаю C ++ и пытаюсь понятьразличные варианты создания и использования конструкторов.Итак, мой первый вопрос: в чем разница между этими двумя объектами:

 class Example{
      Example(int x){myX = x} ;
      private:
         int myX;
 }

Тогда В моем основном методе:

 Example example1 = new Example(5);
 Example example2 = Example(5);
 Example example3(5);

Я знаю, что использование new даст мнединамически размещаемый объект, который позже мне нужно будет удалить.И что example2 будет размещено в стеке, и его не нужно удалять.Но я не совсем понимаю, когда или почему использовать стиль конструктора example3.любая помощь, включающая минимальный жаргон, будет очень цениться, потому что, кажется, я не могу понять это в другом месте.Большое спасибо за любой свет, который вы, ребята, могли бы пролить на меня.

Ответы [ 4 ]

9 голосов
/ 16 октября 2011

Два объявления

Example example2 = Example(5);
Example example3(5);

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

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

Вот полный пример программы для демонстрации:

#include <iostream>

using namespace std;

class Test {
public:
    Test(int x): X(x) {
        cout << "constructor " << X << endl;
    }
    Test(const Test &rhs): X(rhs.X) {
        cout << "copy " << X << endl;
    }
    Test &operator=(const Test &rhs) {
        X = rhs.X;
        cout << "assign " << X << endl;
        return *this;
    }
private:
    int X;
};

int main()
{
    Test t1 = Test(1);
    Test t2(2);
    t2 = t1;
}

и вывод (gcc 4.2.1, OS X Lion):

constructor 1
constructor 2
assign 1

Обратите внимание, как оператор присваивания вызывается только для t2 = t1 (как и ожидалось), но конструктор копирования вообще не вызывается.(Однако, как отмечает Деннис Зиккефуз в комментариях, конструктор копирования должен быть доступен . Попробуйте сделать конструктор копирования private в приведенном выше примере, и компилятор должен отказаться от его компиляции.)

РЕДАКТИРОВАТЬ: Обратите внимание, что gcc на самом деле имеет параметр, который контролирует это поведение:

    -fno-elide-constructors
        The C++ standard allows an implementation to omit creating a
        temporary which is only used to initialize another object of the
        same type.  Specifying this option disables that optimization, and
        forces G++ to call the copy constructor in all cases.
2 голосов
/ 16 октября 2011
Example example1 = new Example(5);

Этот не скомпилируется, так как new Example(5) возвращает указатель на Example.Правильное использование Example * example1 = new Example(5).Необходимо удалить позже.

Example example2 = Example(5);

Этот создает временный экземпляр Example и копирует его в example2, используя (в вашем случае) конструктор копирования по умолчанию.

Example example3(5);

Этот создаетэкземпляр Example в стеке и вызов вашего конструктора.

0 голосов
/ 16 октября 2011

Если у вас есть неявный конструктор, вам разрешается делать либо:

class Example{
  public:
  Example(int x = 0):x(myX){} ; // use initialization list
  private:
     int myX;
};

Example example3(5); // ok
Example example3 = 5; // ok

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

Чтобы быть более конкретным, стиль конструктора в примере 3 обычно является тем случаем, когда ваш конструктор является явным.

class Example{
  public:
  explicit Example(int x = 0):x(myX){} ; // use initialization list
  private:
     int myX;
};

Example example3(5); // ok
Example example3 = 5; // not allowed

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

0 голосов
/ 16 октября 2011

Делая оба

className Object = className(10);
className Object(10);

Я считаю, что на самом деле эквивалентны. Это просто личное предпочтение.

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

Example* example1 = new Example(2);

Говоря об удалении, все они будут вызывать один и тот же деструктор класса.

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