Списки инициализаторов в C++ и инициализация классов. У меня нет конструктора без аргументов, но мне все еще нужно использовать списки инициализаторов?

Хорошо, новичок в C++, я довольно хорошо знаю Java и сейчас пытаюсь изучить C++. В любом случае, вот мой простой класс.

class PolyGon{

    private:
        PointArray aArray;
        static int numberOfInst;

    public:
        PolyGon(Point point[], const int newSize) : aArray(point, newSize){} 
};

Это нормально. И поправьте меня, если я ошибаюсь, но в списке инициализаторов aArray(point, newSize) эквивалентно aArray = new PointArray(point, newSize).

Потому что, когда я пробую тот же самый код, но меняю последнюю строку на:

class PolyGon{

    private:
        PointArray aArray;
        static int numberOfInst;

    public:
        PolyGon(Point point[], const int newSize){aArray = new PointArray(point, newSize)} 
};

Это дает исключение:

нет совпадения для 'operator=' в '((PolyGon*)this)->PolyGon::aArray = (((PointArray*)operator new(8u)), (->PointArray::PointArray(((const Point*) точка), новыйРазмер), ))'|

Если вы хотите увидеть конструктор для PointArray, вот он:

PointArray::PointArray(const Point points[], const int newSize)
{
    size = newSize;

    x = new Point[size];

    for(int i = 0; i < size; i++)
    {
        x[i] = points[i];
    }
}

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

  1. Почему это? Почему я не могу сделать это так, как хотел.
  2. Это правило применимо только к конструктору. Например, я могу сказать «PointArray aArray = new PointArray (point, newSize);» где-нибудь еще?
  3. У меня есть конструктор без аргументов. Так почему это дает мне эту ошибку?

Мой конструктор без аргументов выглядит так:

PointArray(){size = 0; x = new Point[0];}

person user2690235    schedule 16.08.2013    source источник
comment
Что такое класс PointArray?   -  person Neil Kirk    schedule 16.08.2013
comment
И поправьте меня, если я ошибаюсь, но вы ошибаетесь.   -  person Mooing Duck    schedule 16.08.2013
comment
Ты путаешь карту и территорию -- Йода   -  person Yakk - Adam Nevraumont    schedule 16.08.2013


Ответы (3)


Почему это? Почему я не могу сделать это так, как хотел.

В Java aArray будет ссылкой на отдельный объект, который вам нужно будет создать с помощью new.

В C++ вы должны забыть все, что знали об объектной модели Java. aArray — это объект, содержащийся в PolyGon, автоматически создаваемый при создании PolyGon и инициализируемый перед запуском тела конструктора. Если вам нужно предоставить аргументы конструктора, то они должны быть указаны в списке инициализаторов перед телом конструктора; к тому времени, когда вы входите в тело конструктора, оно уже инициализировано.

Это правило применимо только к конструктору. Например, я могу сказать PointArray aArray = new PointArray(point, newSize); где-нибудь еще?

new возвращает указатель на динамический объект; поэтому вы можете использовать его для инициализации указателя (а не объекта):

// Careful! This is a recipe for memory leaks.
PointArray * aArray = new PointArray(point, newSize);

но помните, что если вы создаете что-то с помощью new, вы должны уничтожить это с помощью delete, когда закончите с этим. Сборки мусора нет, поэтому заброшенные динамические объекты дают утечку памяти. Чтобы предотвратить это, по возможности избегайте new и узнайте, как использовать RAII для управления динамическими ресурсами, когда вы они действительно нужны.

Вы также можете создавать объекты без new:

PointArray aArray(point, newSize);

Если это находится внутри блока кода (локальная переменная; технически, в области блока), то она будет автоматически уничтожена, когда программа покинет этот блок. Если он не находится внутри какой-либо функции (глобальной переменной; технически, в области пространства имен), то он длится в течение всей программы (более или менее); но глобальные обычно считаются плохой идеей.

У меня есть конструктор без аргументов. Так почему это дает мне эту ошибку?

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

PolyGon(Point point[], const int newSize) {
    aArray = PointArray(point, newSize);  // No new
} 

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

person Mike Seymour    schedule 16.08.2013

PolyGon(Point point[], const int newSize) : aArray(point, newSize){} 

Это говорит: «В качестве первой части построения объекта PolyGon создайте его внутренний aArray с параметрами point, newSize. Я намеренно использую здесь слово «внутренний». Чтобы сделать его более ясным, я собираюсь использовать объект «человек» в качестве аналогия. В Java объекты ссылаются друг на друга. При создании нового объекта человека вы создаете новый (отдельный) объект имени, а затем сообщаете человеку, что теперь он владеет этим именем.

В C++ это даже отдаленно не работает. Члены (кожа и кровь) на самом деле являются частью самого объекта. Делая человека объектом, вы должны одновременно сделать объект кожи и объект крови, поскольку вы создаете человека, вы не можете сделать их по отдельности, а затем сказать человеку, что теперь он владеет этой кожей. Точно так же вы не можете удалить их или уничтожить, не уничтожив человека. Тело конструктора — это процесс оживления (рождения).

Это объясняет, почему члены должны быть созданы до начала тела конструктора (человек не может начать «жить» до тех пор, пока кожа не будет завершена), и почему вы не можете дать члену объект new (не можете забрать кожу человека и дайте им другой) Член является буквально частью объекта. Список инициализаторов создает члены объекта, которые буквально являются частью объекта и необходимы для того, чтобы объект "жил". (аналогия человека растет в утробе матери) После того, как части собраны и готовы к работе, наконец начинается тело конструктора, которое начинает процесс окончательного «оживления» объекта (рождение).

Из спецификации C++11, раздел § 3.8/1
Время жизни объекта типа T начинается, когда ... его инициализация завершена. Время жизни объекта типа T заканчивается, когда... начинается вызов деструктора.

Так что я совершенно не придумал терминологию «жизни».

Вернемся к коду C++:

PolyGon(Point point[], const int newSize) 
//when making a new PolyGon
: aArray(point, newSize)
//construct it's internal aArray member at the same time
{}
//No additional steps needed to make it "live".

О ключевом слове new:
Ключевое слово new требуется для всего в Java, потому что Java хранит все объекты отдельно, независимо от того, что происходит, поэтому вы используете new, несмотря ни на что. В C++ мы можем создавать объекты буквально внутри других объектов или в памяти стека. Нам не нужна система, чтобы создать нам объект new, нам нужно построить объект в пространстве, которое у нас уже есть. В качестве альтернативы, если вам абсолютно необходим отдельный или динамический объект, вы можете использовать new для создания нового объекта в куче.

{
    PolyGon inst; //this construts a PolyGon object _in_ the stack space
                 //we refer to this object by the name "inst"
    inst.print_name(); //work with inst directly
    PolyGon* ptr = new PolyGon(); //this constructs a brand new PolyGon _in_ the "heap"
                                  //and a pointer _in_ the stack space
                                  //and stores the position of the PolyGon in the pointer
                                  //we refer to this _pointer_ by the name "ptr"
    ptr->print_name(); //call print_name on the object that ptr points at.
    delete ptr; //delete the thing that ptr points at
    ptr = &inst;  //now we store the address of inst in the ptr pointer object
    ptr->print_name(); //call print_name on inst
} //inst was in the stack, so as the stack unwinds, "inst" is destructed automatically
  //ptr also destructed. Destructing pointers DOES NOT destroy the things they point at
person Mooing Duck    schedule 16.08.2013

aArray(point, newSize) эквивалентен aArray = new PointArray(point, newSize).

No.

PointArray aArray;

aArray тип PointArray, но не PointArray *. Оба являются разными типами в C++. Итак, вы получаете ошибку компиляции, когда пытаетесь присвоить PointArray * переменной-члену aArray.

person Mahesh    schedule 16.08.2013