По умолчанию против неявного конструктора в С++

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

struct Test {
  Test(int n=0) { }
};

Можете ли вы описать в этих терминах, что есть:

  • Тестирование t1;
  • Тест t2();
  • Тестирование t3 = 3;
  • Тест t4 (4);
  • Тест t5 = Тест (5);

?

Ответ 1

Термины default и implicit, говоря о конструкторе, имеют следующее значение:

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

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

    • неявно объявленный конструктор, который является конструктором по умолчанию или копией, который будет объявлен для всех пользовательских классов, если не указан какой-либо пользовательский конструктор (по умолчанию), или нет конструктора копирования (копия). То есть класс без конструкторов, объявленных пользователем, имеет один конструктор по умолчанию, неявно объявленный.

    • неявно определенный конструктор - это неявно объявленный конструктор, который используется (odr-used 1 в языке и для которого компилятор предоставит определение.

     

    struct test
    {
        test(int i = 0) { }
        // test(test const&) implicitly declared here
    };
    
    struct test2 { };      // implicitly declared: test2(), test2(test2 const&)
    
    int main()
    {
        test t;
    
        test copy(t);      // causes *definition* of the implicitly
                           // declared copy constructor
    
        test2 t2;          // causes *definition* of test2::test2()
    
        test2 copy2(t2);   // causes *definition* of test2::test2(test2 const&)
    }
    

В простых терминах конструктор по умолчанию используется, если его можно вызвать без аргументов. Конструктор неявный (объявлен/определен), если он не предоставлен пользователем, но объявлен/определен.

В зависимости от конкретных случаев:

Test t1;

Использует конструктор по умолчанию Test(int = 0), который не является неявным.

Test t2();

Это странная причуда языка, она объявляет функцию, которая не принимает аргументов и возвращает объект Test.

Test t3 = 3;

Это называется копией-инициализацией и эквивалентно составу неявного преобразования * от 3 до Test и скопируйте построение t3 из результата преобразования. Это будет использовать конструктор Test(int) для преобразования, а затем неявно определенный (и объявленный) экземпляр копии. Примечание: компилятор может оптимизировать копию, но должен убедиться, что конструктор копирования доступен (спецификаторы доступа) и может быть определен.

Test t4(4);

Использует конструктор Test(int), который в этом случае не действует как конструктор по умолчанию.

Test t5 = Test(5);

Эквивалентен случаю Test t3 = 3, с той лишь разницей, что преобразование из 5 в Test является явным в этом случае. В этом примере это не имеет значения, но если конструктор был помечен как explicit, эта строка будет компилироваться, а случай t3 завершится с ошибкой.


*) Еще одно использование неявного, в данном случае ссылающегося на то, что преобразование из 3 в Test явно не запрашивается в коде. Сравните это с t5, где программа-программист явно запрашивает преобразование: Test(5).

Ответ 2

Кажется, вы смешиваете некоторые термины. Конструктор по умолчанию - это тот, который не принимает никаких параметров, неявный вызов - это когда вы вызываете конструктор напрямую.

В любом случае:

1) Тест t1;

Конструктор по умолчанию.

2) Тест t2();

Объявление функции.

3) Испытание t3 = 3;

Инициализация копирования. Вызовите конструктор преобразования, создайте временный Test из 3 и используйте конструктор копирования для создания t3.

4) Испытание t4 (4);

Прямая инициализация. Использует конструктор преобразования напрямую.

5) Тест t5 = Тест (5);

Инициализация копирования. Аналогично 3).