Явное присвоение против неявного присвоения

Я читаю учебник по C ++, но на самом деле он не дал мне разницы (помимо синтаксиса) между ними. Вот цитата из учебника.

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

int nValue = 5; // explicit assignment

Вы также можете присваивать значения переменным, используя неявное присваивание:

int nValue(5); // implicit assignment

Несмотря на то, что неявные присваивания очень похожи на вызовы функций, компилятор отслеживает, какие имена являются переменными, а какие - функциями, чтобы их можно было правильно разрешить.

Есть разница? Одно предпочтительнее другого?


person Freesnöw    schedule 19.07.2011    source источник
comment
Это не декларация, это определение. Откажитесь от этого учебника и прочтите хорошую книгу. Мышление на C ++ бесплатно и доступно со страницы автора.   -  person Cat Plus Plus    schedule 19.07.2011
comment
@Cat Plus Plus: это определение, но это не значит, что это не декларация.   -  person James McNellis    schedule 19.07.2011
comment
@JamesMcNellis: Предполагается, что это учебное пособие, и вызов объявлений определений не помогает избавиться от путаницы между ними. Может, я сегодня просто капризничаю. :П   -  person Cat Plus Plus    schedule 19.07.2011
comment
@Cat Plus Plus: Сказать, что что-то не то, что есть на самом деле, тоже не поможет избавиться от путаницы.   -  person James McNellis    schedule 19.07.2011
comment
Речь идет о следующем руководстве: learncpp.com / cpp-tutorial /   -  person augustin    schedule 05.02.2015
comment
Забавно, что ни то, ни другое не является назначением.   -  person juanchopanza    schedule 25.09.2015


Ответы (3)


Первый предпочтительнее для примитивных типов, таких как int; второй - с типами, у которых есть конструктор, потому что он делает вызов конструктора явным.

Например, если вы определили class Foo, который может быть построен из одного int, тогда

Foo x(5);

предпочтительнее

Foo x = 5;

(Вам все равно понадобится прежний синтаксис, когда передается более одного аргумента, если только вы не используете Foo x = Foo(5, "hello");, который просто уродлив и выглядит так, как будто вызывается operator=.)

person Fred Foo    schedule 19.07.2011
comment
Стоит упомянуть, что при построении синтаксиса нужно быть осторожным с большинством неприятных синтаксических разборов. - person Cat Plus Plus; 19.07.2011
comment
Также обратите внимание, что Foo x = 5 будет работать, только если Foo::Foo(int) не отмечен explicit. - person Vitus; 19.07.2011
comment
... (продолжение комментария @Vitus) и Foo конструктор копирования доступен. - person David Rodríguez - dribeas; 20.07.2011

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

инициализация копирования (T t = u;) эквивалентна конструкции копирования из временного объекта типа T, который был неявно преобразован из u в t. С другой стороны, прямая инициализация эквивалентна прямому вызову соответствующего конструктора.

Хотя в большинстве случаев разницы не будет, если конструктор, принимающий u, объявлен explicit или если copy-constructor недоступен, то инициализация копирования завершится ошибкой:

struct A {
   explicit A( int ) {}
};
struct B {
   B( int ) {}
private:
   B( B const & );
};
int main() {
   A a(1);      // ok
   B b(1);      // ok
// A a2 = 1;    // error: cannot convert from int to A
// B b2 = 1;    // error: B( B const & ) is not accessible
}

По некоторым историческим соображениям, изначально примитивные типы должны были быть инициализированы с помощью copy-initialization. Когда * список-инициализаторов * были добавлены к языку для инициализации атрибутов членов из класса, было решено, что примитивные типы должны быть инициализированы с тем же синтаксисом, что и классы, чтобы синтаксис в списке инициализаторов был единообразным и простым. В то же время разрешение инициализации классов с помощью copy-initialization приближает определяемые пользователем типы к примитивным типам. Различия в двух форматах инициализации очевидны: int a = 5.0; обрабатывается как преобразование из 5.0 в int, а затем инициализация a из int. То же самое и с пользовательскими типами: T u = v; обрабатывается как преобразование из v в T, а затем копируется построение u из этого преобразованного значения.

person David Rodríguez - dribeas    schedule 19.07.2011

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

int nValue = 5; // assignment syntax

и

int nValue(5); // construction syntax

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

Для типов классов я предпочитаю строительный синтаксис, поскольку он исключает существование функции-конструктора.

person Evan Teran    schedule 19.07.2011
comment
Стандарт (N3242) вызывает синтаксисы T x = a copy-initialization и T x(a) direct-initialization. Оба являются допустимыми способами вызова конструктора T::T(a). - person Kerrek SB; 19.07.2011