Определение конструктора Синтаксис C ++

В чем разница между этими двумя объявлениями конструкторов:

class Fruit {
  private:
    int price;

  public:
    Fruit(int x): price(x)
    {
    }    
};

VS

class Fruit {
  private:
    int price;

  public:
    Fruit(int x)
    {
        price = x;
    }
};

Первый, который я видел в случае наследства.

Насколько мне известно, это не повторяющийся вопрос. Если найдете, не стесняйтесь закрыть этот вопрос.


person pseudo_teetotaler    schedule 10.11.2018    source источник
comment
Однако оба не будут компилироваться, если вы не добавите; после объявления: int price;   -  person Aganju    schedule 11.11.2018


Ответы (4)


Первый инициализирует price с помощью x, а второй инициализирует price его значением по умолчанию (по умолчанию создает его; в случае переменной int инициализируется неопределенным значением), а затем копирует x в price.

Другими словами, первый почти эквивалентен

int price = x;

где второй почти эквивалентен

int price;

price = x;

В случае переменной int (учитывая также оптимизацию компилятора) я полагаю, что нет эффективной разницы.

Но когда price - сложный объект, требующий больших затрат на строительство, разница может быть большой.

Как лучше объяснит Питер: «Разница между двумя сложными объектами заключается не в стоимости строительства. Вопрос в том, является ли переназначение после инициализации по умолчанию более затратным, чем инициализация в один шаг. На практике двухэтапный процесс часто бывает дороже. (различными способами), чем прямая инициализация, так как может потребоваться очистить настройку по умолчанию, чтобы изменить значение. Есть также проблемы с безопасностью исключений - что, если переназначение или построение вызовет исключение ».

Поэтому обычно настоятельно рекомендуется использовать первое решение (инициализировать объект с правильным значением).

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

Действительно ты не можешь писать

int const  price;

price = x;  // error: price is const
person max66    schedule 10.11.2018
comment
Возможно, стоит отметить, что для определяемых пользователем типов второй параметр вызывает конструктор по умолчанию, и это может быть не так, как int price;. - person Quimby; 11.11.2018
comment
Ой, ты только что добавил :) - person Quimby; 11.11.2018
comment
Разница между двумя сложными объектами заключается не в стоимости строительства. Вопрос в том, будет ли переназначение после инициализации по умолчанию более затратным, чем инициализация за один шаг. На практике двухэтапный процесс часто дороже (по разным причинам), чем прямая инициализация, поскольку может потребоваться очистить настройку по умолчанию, чтобы изменить значение. Есть также проблемы с безопасностью исключений - что, если переназначение или построение вызовет исключение. - person Peter; 11.11.2018
comment
@Peter - Я пытался объяснить этот момент, но ваше объяснение гораздо более ясно, чем мое. Я просто скопировал это. Спасибо. - person max66; 11.11.2018

Первый использует список инициализации, а другой - нет, и присваивает x члену данных price внутри тела конструктора.

Обычно мы предпочитаем использовать списки инициализации и сделайте тело конструктора максимально простым.

person gsamaras    schedule 10.11.2018
comment
К сожалению, синтаксис списков инициализации несколько уродлив и исключает использование промежуточных значений r. - person Dai; 11.11.2018
comment
Действительно @Dai, но все же полезно! - person gsamaras; 11.11.2018
comment
Это не так. Невозможно инициализировать член данных внутри тела конструктора. Это задание. - person Lightness Races in Orbit; 11.11.2018
comment
@LightnessRacesinOrbit хороший улов, поправил, спасибо! - person gsamaras; 11.11.2018

Чтобы добавить к другим ответам, первый вариант - это естественный способ инициализировать const членов

struct C
{
    const int val;

    C() : val(5) // Perfectly OK
    {
    }

    C(int) // error: uninitialized const member in 'const int' [-fpermissive]
    {
        val = 5 // error: assignment of read-only member 'C::val'
    }
};

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

struct D
{
    struct not_default_constructible
    {
        not_default_constructible(int)
        {
        }
    } var;

    int& ref;

    D(int a) : ref(a), var(5) // Legal
    {
    }

    D(int a, char) // error: uninitialized reference member in 'int&' [-fpermissive]
    { // error: no matching function for call to 'D::not_default_constructible::not_default_constructible()'
        ref = a;
    }
};
person Zereges    schedule 10.11.2018
comment
Точно так же член типа класса, когда этот класс не имеет доступного конструктора по умолчанию, может быть инициализирован только с помощью mem-initializer-list. - person aschepler; 11.11.2018

Второй не инициализирует price с x при создании Fruit, который поэтому по умолчанию создает его. Как если бы вы написали:

class Fruit{
private :
    int price

public:
    Fruit(int x) :
        price() // default constructed
    {
        price = x
    }    
}

Для эффективности лучше инициализировать значение, которое вы хотите ему присвоить.

person Ted Lyngmo    schedule 10.11.2018