2015-09-14 3 views
1

Я не уверен, правильно ли я назвал свой вопрос, поэтому не стесняйтесь исправлять меня. Я считаю, что:Разница между инициализацией в списке инициализации и инициализацией в конструкторе

  1. Инициализация в списке инициализации эквивалентно
    int a = a;

  2. Инициализация в конструкторе эквивалентно
    int a; a = a;

Но я до сих пор не могу понять из-за причины следующего выпуска:

#include <iostream> 
using namespace std; 

class test 
{ 
    int a,b; 
    public: 

    /* 
    test(int a, int b): a(a), b(b) {}   //OUTPUT: 3 2 
    test(int a, int b) { a = a; b = b;}  //OUTPUT: -2 1972965730 
    test(int c, int d) { a = c; b = d;}  //OUTPUT: 3 2 
    Hence it does work without this pointer. Unless the variable names are same 
    */ 

    void print() { cout<<a<<" "<<b<<"\n";} 
}; 

int main() 
{ 
    test A(3,2); 
    A.print(); 
    return 0; 
} 

правок:

  1. Как M.M отметил: Эквивалент a(a) является this->a = a.

  2. Стоит читать: Why should I prefer to use member initialization list?

  3. Два обходные пути:

    test(int a, int b) { this->a = a; this->b = b;} 
    test(int a, int b) { test::a = a; test::b = b;} 
    
+1

Есть 2 отличия: Давать значение в теле не инициализировать, так как значение уже инициализировано (за исключением примитивных типов). В вашем случае во второй версии элемент 'a' затенен параметром a, но в списке инициализации это не так (поскольку вы можете инициализировать только в списке только для списка инициализации). – Melkon

+3

Эквивалент 'a (a)' is 'this-> a = a;' –

+0

Не используйте одинаковые имена для членов класса и параметры методов. Это не стоит этих проблем. – Melebius

ответ

2

В списке инициализации синтаксис таким образом, что каждое переменное имя вне скобок () является класса член а. То, что входит в parens, - это то, что происходит в области видимости - будь то член класса или параметр конструктора. Параметр скроет член класса.

Таким образом, вы можете спокойно сделать:

class MyClass 
{ 
    int i; 
    MyClass(int i): i(i) {} 
    //    ^-must be class member 
}; 

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

Что происходит внутри в скобки задается один и тот же объем, как то, что происходит внутри тела конструктора.

Итак:

class MyClass 
{ 
    int i; 
    MyClass(int i) 
    { 
     i = i; // BOTH of those are the parameter i 
    } 
} 

параметр называется i является скрываетсякласса член называется i так класса член никогда не получает доступ в теле конструктора.

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

class MyClass 
{ 
    int i; 
    MyClass(int i) 
    { 
     // now we set class member i to parameter i 
     this->i = i; 
    } 
} 

Все, что позаботился о вас в синтаксисе списка инициализатора:

//    v-this parameter is hiding the class member 
    MyClass(int i): i(i) {} 
    //    ^-must be the class member 

список инициализаторов в основном делает: this->i = i для вас.

Вы должны всегда инициализировать элементы в списке инициализаторов если возможно.

9
test(int a, int b) { a = a; b = b;} 

Это не правильно. Он ничего не делает для членов данных. Он должен быть

test(int a, int b) { this->a = a; this->b = b;} 
+0

Простое изменение имени переменной работает без этого: i.e test (int c, int d) {a = c; b = d;} –

+2

@PrayanshSrivasta Конечно, и так делают разные вещи. Использование списка инициализаторов - правильный путь. – EJP

0

Попробуйте заменить test(int a, int b) { a = a; b = b;} с test(int a, int b) { this->a = a; this->b = b;} Мой компилятор (MSVC) производит желаемый результат.

0

Каждая функция вводит новую область. Когда вы определяете свой конструктор как

test(int a, int b) { a = a; b = b; } 

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

При объявлении конструктора, как

test(int c, int d) { a = c; b = d; } 

вы не имеете эту проблему, потому что больше не называющие столкновения.

В предложенном исправить, то же самое рассуждение применимо:

test(int a, int b) { this->a = a; this->b = b; } 

Вы явно оговориться, что л.ш. a является членом класса, используя this указатель, который неявно передается каждой функции члена, в том числе конструктор. Однако этот код не эквивалентен инициализации с помощью списка инициализации.Вы были правы в вашем вопросе:

  1. Инициализация в списке инициализации эквивалентно int a = a;
  2. Инициализация в конструкторе эквивалентно int a; a = a;

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

Таким образом, вы всегда должны предпочесть использовать список инициализации:

test(int a, int b): a(a), b(b) {}