Явное назначение против неявного назначения - PullRequest
13 голосов
/ 19 июля 2011

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

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

int nValue = 5; // explicit assignment

Вы также можете присваивать значения переменным с помощью неявного присваивания:

int nValue(5); // implicit assignment

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

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

Ответы [ 3 ]

13 голосов
/ 19 июля 2011

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

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

Foo x(5);

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

Foo x = 5;

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

6 голосов
/ 19 июля 2011

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

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

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

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

3 голосов
/ 19 июля 2011

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

int nValue = 5; // assignment syntax

и

int nValue(5); // construction syntax

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

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

...