名前 (識別子) の型をコンパイラに伝えるのが宣言で、その名前が参照している実体 (メモリ) を確保するのが定義です。
| 分類 | 宣言 | 定義 |
|---|---|---|
| 変数 | extern int x; |
int x; |
| 関数 | int Func(); |
int Func() { } |
| クラス | class MyClass; |
class MyClass { }; |
名前の定義は1つでなければなりませんが、宣言はいくつあっても構いません。ただしすべての宣言は、参照している実体の型が一致している必要があります。
たいていの宣言は定義でもあり、宣言と同時に実体も定義しています。
int x1; // 変数の定義 int x2 = 1; // 初期化子を伴う、変数の定義 int* x3; // ポインタの定義
int Func() { return; } // 関数定義
class MyClass { int a, b; }; // クラス定義
template<class T> T Func() { } // template宣言
typedef Type1<int> Type2; // typedef宣言
enum MyEnum { a, b, c }; // 列挙型の定義
namespace MyNamespace { int a; } // 名前空間を用いた、変数の定義
また初期値を与える場合はすべて定義であり、
extern int x;
とすると宣言ですが、
extern int x = 1;
として初期値を与えるとexternは無視され、定義となります。
次のように定義するとき、
int x = 1;
これを構成する要素は、それぞれ
の意味を持ちます。
| int x = 1; | 等号と、それに続く式 |
| MyStruct s(1, 2); | 丸かっこ内の式 (引数付きコンストラクタ) |
| MyStruct s{1, 2}; | 波かっこで囲まれた、初期化子リスト (initializer list) (省略可能) |
| MyStruct s{}; |
struct MyStruct
{
int i;
char c;
};
int x; // 0 に初期化される (ファイル スコープ)
int main()
{
static float f; // 0.000000000 に初期化される (静的な変数)
double d{}; // 0.00000000000000000 に初期化される (初期化子リスト)
int* ptr{}; // nullptr に初期化される (初期化子リスト)
char s_array[3]{ 'a', 'b' }; // 値が指定されていない3番目の要素は、'\0' に初期化される
int int_array[5] = { 8, 9, 10 }; // 値が指定されていない4番目と5番目の要素は、0 に初期化される
MyStruct a_struct{}; // i = 0, c = '\0'
}
初期化の種類 - 初期化子 | MSDN
クラスや構造体は、初期化子の省略またはnew演算子によって既定のコンストラクタが呼び出され、それによって既定値に初期化されます。
MyClass myClass1; // 初期化子の省略 MyClass* myClass2 = new MyClass; // new演算子