Constメンバーをコンストラクターで変更できるのはなぜですか。
メンバーの「定数」をオーバーライドする初期化の標準ルールはありますか?
struct Bar {
const int b = 5; // default member initialization
Bar(int c):b(c) {}
};
Bar *b = new Bar(2); // Problem: Bar::b is modified to 2
// was expecting it to be an error
何か案は?
これは変更(または割り当て)ではなく、 初期化 です。例えば.
struct Bar {
const int b = 5; // initialization (via default member initializer)
Bar(int c)
:b(c) // initialization (via member initializer list)
{
b = c; // assignment; which is not allowed
}
};
const
データメンバーは変更または割り当てできませんが、メンバー初期化子リストまたはデフォルトのメンバー初期化子を介して初期化することができます(必要です)。
デフォルトのメンバー初期化子とメンバー初期化子の両方が同じデータメンバーで提供されている場合、デフォルトのメンバー初期化子は無視されます。 b->b
が値2
で初期化されるのはそのためです。
メンバーにデフォルトのメンバー初期化子があり、コンストラクターのメンバー初期化リストにも表示されている場合、デフォルトのメンバー初期化子は無視されます。
一方、デフォルトのメンバー初期化子は、データメンバーがメンバー初期化子リストで指定されていない場合にのみ有効になります。例えば.
struct Bar {
const int b = 5; // default member initialization
Bar(int c):b(c) {} // b is initialized with c
Bar() {} // b is initialized with 5
};
Songyuanyaoの素晴らしい答えに加えて、コンストラクターで初期化できないconst
データメンバーが必要な場合は、メンバーstatic
を作成できます。
struct Bar {
static const int b = 5; // static member initialization
Bar(int c)
:b(c) // Error: static data member can only be initialized at its definition
{
b = c; // Error: b is read-only
}
};
C++ 17では、inline
にすることでこれをさらに改善できます。
struct Bar {
inline static const int b = 5; // static member initialization
Bar(int c)
:b(c) // Error: static data member can only be initialized at its definition
{
b = c; // Error: b is read-only
}
};
これにより、ODRで問題が発生しなくなります。
あなたがするとき:
_struct Bar {
const int b = 5; // default member initialization
...
};
_
デフォルトのコンストラクターでこれを行うようコンパイラーに指示しています。
_...
Bar() : b(5)
{}
...
_
デフォルトのコンストラクタを提供したかどうかに関係なく。 default-constructor andの初期割り当てを指定すると、コンパイラのデフォルト割り当てコード(つまり、b(5)
)がオーバーライドされます。宣言でのデフォルトの初期化/割り当ては、複数のコンストラクターがあり、すべてのコンストラクターでconstメンバーを割り当てることができる場合とできない場合に役立ちます。
_...
Bar() = default; // b=5
Bar(int x) : b(x) // b=x
Bar(double y) : /*other init, but not b*/ // b=5
...
_