Понимание конструктора C++

Рассмотрим этот конструктор: Packet() : bits_(0), datalen_(0), next_(0) {}

Обратите внимание, что bits_, datalen_ а также next_ поля в пакете класса определены следующим образом:

u_char* bits_;
u_int datalen_;
Packet* next_;

Что означает эта часть конструктора? bits_(0), datalen_(0), next_(0)

3 ответа

Решение

Это список инициализаторов, он устанавливает указанные значения.

Packet() : bits_(0), datalen_(0), next_(0)
{
    assert( bits_ == 0 );
    assert( datalen_ == 0);
    assert( next_ == 0);
}
//...
Packet()
{
    //bits_ , datalen_, next_ uninitialized here
}

Некоторые участники (const члены или определяемые пользователем члены класса без конструкторов по умолчанию) не могут быть инициализированы вне списка инициализатора:

class A
{
    const int x;
    A() { x = 0; }  //illegal
};

class A
{
    const int x;
    A() : x(0) { }  //legal
};

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

class B
{
public:
   B() { cout << "default "; }
   B(int) { cout << "b"; }
};

class A
{
   B b;
   A() { b = B(1); }   // b is initialized twice - output "default b"
   A() : b(1) { }      // b initialized only once - output "b"
}; 

Это предпочтительный способ инициализации членов.

Это означает, что сначала bits_, затем datalen_ и, наконец, next_ получат значение 0. Т.е. следующие 2 фрагмента кода полностью эквивалентны:

Packet()
     : bits_(0)
     , datalen_0)
     , next_(0)
{
}

и это:

Packet()
{
    bits_ = 0;
    datalen_ = 0;
    next_ = 0;
}

Осторожно, хотя. Порядок инициализации определяется порядком объявления членов. Т.е. следующий код не будет работать так, как ожидалось:

struct Packet
{
    int first;
    int second;

    Packet()
        : second(0)
        , first(second)
    {
    }
};

это будет эквивалентно этому:

struct Packet
{
    int first;
    int second;

    Packet()
    {
        first = second;
    second = 0;
    }
};

второй получит 0, но первый не получит

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

Packet()
{
    bits_ = nullptr;  // or 0 or NULL pre-C++11
    datalen_ = 0;
    next_ = nullptr;
}

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

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

Другие вопросы по тегам