Зачем мне нужна функция конструктора?

#include<iostream>
using namespace std;

class A {
public:
    int i;
};

int main() {
  const A aa;  //This is wrong, I can't compile it! The implicitly-defined constructor does not initialize ‘int A::i’
}

когда я использую

class A {
public:
  A() {}
  int i;
};

Это нормально! Я могу скомпилировать его! почему я не могу скомпилировать его, когда я использую неявно определенный конструктор?

Ответ 1

почему неявный конструктор не работает?

Он работает, но одно из правил языка состоит в том, что его нельзя использовать для инициализации объекта const, если он не инициализирует всех членов; и он не инициализирует членов с тривиальными типами, такими как int. Это обычно имеет смысл, поскольку const не может дать им значение позже.

(Это небольшое упрощение, см. комментарии к главе и стиху из языкового стандарта.)

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

Если вы хотите установить его на ноль, вы можете инициализировать объект значением:

const A aa {};    // C++11 or later
const A aa = A(); // historic C++

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

A() : i(whatever) {}

Ответ 2

почему неявный конструктор не работает?

Потому что стандарт С++ так говорит:

[dcl.init], пункт 7: Если программа вызывает инициализацию по умолчанию объекта типа const-type T, T должен быть типом класса с предоставленным пользователем конструктором по умолчанию.

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

Чтобы инициализировать объект с контентом, вам необходимо иметь предоставленный пользователем конструктор по умолчанию или использовать инициализатор:

const A aa = A();

Здесь объект aa инициализируется выражением A(), которое является инициализированным значением объектом. Вы можете инициализировать тип класса без конструктора по умолчанию, поскольку инициализация значения будет устанавливать значения равными нулю, если для типа не существует конструктора по умолчанию.

Однако правило в стандарте слишком строгое, поскольку оно запрещает использование неявно определенных конструкторов, даже если нет элементов данных, или все члены данных имеют разумные конструкторы по умолчанию, поэтому есть отчет о дефектах по сравнению с стандартом, предлагающим изменить его, см. вопрос 253.

Ответ 3

Вы не указываете, какой компилятор вы используете. Я пробовал это с VS2012 и получил предупреждение C4269.

Причина, по которой это проблема, состоит в том, что aa - const. Поскольку вы не определили конструктор, используется значение по умолчанию, и поэтому i может быть любым. Он также не может быть изменен (поскольку aa является константой).

Если вы определяете конструктор, предполагается, что вы довольны инициализацией i. Хотя в этом случае вы фактически не изменили поведение.

Из этой страницы MSDN

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

Ответ 4

Потому что i не инициализирован.

class A 
{ 
    public:
    A()
    {
        i =0;
    }
    int i;
};

"Неявный конструктор" означает автоматически созданный для вас конструктор и генерирует ошибку, поскольку он понимает, что не может инициализировать значение i. Это может быть конструктор no-args, конструктор копирования или (как на С++ 11) конструктор перемещения.

Ответ 5

почему неявный конструктор не работает?

Он работает отлично, но он не определяет, какие значения по умолчанию неявно (и как таковые, он вызывает только конструкторы по умолчанию для его членов, но не для типов POD).

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

Создание стандартного (неявного) конструктора инициализирует элементы POD с выбранным значением (например, нуль), добавит дополнительные вычислительные циклы (и замедлит вашу программу вниз), когда вам это не понадобится. С++ предназначен для того, чтобы вести себя так, как будто вы (программист) знаете, что вы делаете (т.е. Если вы явно не инициализируете своих членов, компилятор предполагает, что вам все равно, какое значение по умолчанию вы получите).