このコンストラクターについて考えてみましょう。Packet() : bits_(0), datalen_(0), next_(0) {}
bits_
、およびは、次のように定義されたクラスPacketのフィールドであることにdatalen_
注意next_
してください。
u_char* bits_;
u_int datalen_;
Packet* next_;
コンストラクターのこの部分はどういう意味ですか?bits_(0), datalen_(0), next_(0)
このコンストラクターについて考えてみましょう。Packet() : bits_(0), datalen_(0), next_(0) {}
bits_
、およびは、次のように定義されたクラスPacketのフィールドであることにdatalen_
注意next_
してください。
u_char* bits_;
u_int datalen_;
Packet* next_;
コンストラクターのこの部分はどういう意味ですか?bits_(0), datalen_(0), next_(0)
これは初期化リストであり、指定された値に値を設定します。
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;
}
};
したがって、2番目は0を受け取りますが、最初は受け取りません
これは初期化リストと呼ばれ、括弧内に指定された値でフィールドを初期化します。以下は同じ最終効果を達成します:
Packet()
{
bits_ = nullptr; // or 0 or NULL pre-C++11
datalen_ = 0;
next_ = nullptr;
}
違いは、割り当てを行っている私の例では、フィールドはデフォルトのコンストラクターによってすでに構築されているということです。
デフォルトのコンストラクターがないユーザー定義型の場合、コンストラクターにいくつかのパラメーターを指定する必要があるため、初期化子リストが唯一の方法です。