宣言と定義 (C++)

C++ プログラムは、変数、関数、型、名前空間などのさまざまなエンティティで構成されています。 これらの各エンティティは、使用する前に宣言する必要があります。 宣言は、エンティティの一意の名前と、その型およびその他の特性に関する情報を指定します。 C++ では、名前が宣言されているポイントは、コンパイラに表示される位置です。 コンパイル単位の後の時点で宣言されている関数またはクラスを参照することはできません。 変数は、使用されるポイントの前にできるだけ近いものとして宣言する必要があります。

次の例は、いくつかの宣言を示しています。

#include <string>

int f(int i); // forward declaration

int main()
{
    const double pi = 3.14; //OK
    int i = f(2); //OK. f is forward-declared
    C obj; // error! C not yet declared.
    std::string str; // OK std::string is declared in <string> header
    j = 0; // error! No type specified.
    auto k = 0; // OK. type inferred as int by compiler.
}

int f(int i)
{
    return i + 42;
}

namespace N {
   class C{/*...*/};
}

5 行目では main 関数が宣言されています。 7行目では、pi という名前の const 変数が宣言され、初期化されています。 8 行目では、整数 i が宣言され、関数 f によって生成された値で初期化されます。 名前 f は、3 行目の転送宣言によりコンパイラから参照できます。

9 行目では、型 Cobj という名前の変数が宣言されています。 ただし、この宣言では、C がプログラムの後半まで宣言されていないため、前方宣言されていないため、エラーが発生します。 このエラーを修正するには、main の前に C定義全体を移動する、またはその転送の宣言を追加します。 この動作は、C# などの他の言語とは異なります。 これらの言語では、関数とクラスは、ソース ファイル内の宣言のポイントの前に使用できます。

10 行目では、std::string 型の str という名前の変数が宣言されています。 この名前 std::string は、stringヘッダー ファイルに導入されており、1 行目のソース ファイルにマージされるため、表示されます。 std は、string クラスが宣言されている名前空間です。

11 行目では、名前 j が宣言されていないため、エラーが発生します。 宣言は、JavaScript などの他の言語とは異なり、型を提供する必要があります。 12 行目では、auto キーワードが使用されます。これにより、コンパイラは、初期化された値に基づいての k 型を推論するように指示します。 この場合、コンパイラは型の int を選択します。

宣言のスコープ

宣言によって導入される名前は、宣言が行われるスコープ内で有効です。 前の例では、main 関数内で宣言されている変数はローカル変数です。 メインの外部にある i という名前の別の変数をグローバル スコープで宣言し、それを別のエンティティにすることができます。 ただし、このような名前の重複によって、プログラマの混乱やエラーが発生する可能性があるため、回避する必要があります。 21 行目では、クラス C は名前空間 N のスコープ内で宣言されています。 名前空間を使用すると、名前の競合を回避できます。 ほとんどの C++ 標準ライブラリ名は、std 名前空間内で宣言されています。 スコープ規則と宣言の使用方法の詳細については、「スコープ」を参照してください。

定義

関数、クラス、列挙型、定数変数を含む一部のエンティティは、宣言されるだけでなく定義される必要があります。 定義により、プログラムの中でエンティティが使用されている場合にコンピューター コードを生成するために必要なすべての情報がコンパイラに提供されます。 前の例では、行 3 に関数 f の宣言が含まれていますが、関数の定義は 15 ~ 18 行目に用意されています。 21 行目では、クラス C が宣言および定義されています (定義されているように、クラスは何も実行しません)。 定数変数は、その変数が宣言されているのと同じステートメント内で、値が割り当てられている他の単語に定義されている必要があります。 int などの組み込み型の宣言は自動的に定義されます。これは、コンパイラが割り当てられる領域の量を認識するためです。

次の例は、定義でもある宣言を示しています。

// Declare and define int variables i and j.
int i;
int j = 10;

// Declare enumeration suits.
enum suits { Spades = 1, Clubs, Hearts, Diamonds };

// Declare class CheckBox.
class CheckBox : public Control
{
public:
    Boolean IsChecked();
    virtual int     ChangeState() = 0;
};

次に、定義ではない宣言をいくつか示します。

extern int i;
char *strchr( const char *Str, const char Target );

Typedef と using ステートメント

以前のバージョンの C++ では、typedef キーワードを使用して、別の名前の別名である新しい名前を宣言しています。 たとえば、型 std::stringstd::basic_string<char> の別の名前です。 プログラマは、実際の名前ではなく typedef 名を使用するのが明らかです。 最新の C++ では、using キーワードは typedef よりも優先されますが、概念は同じです。新しい名前がエンティティに対して宣言され、既に宣言され、定義されています。

静的クラス メンバー

静的クラスのデータ メンバーは、クラスのすべてのオブジェクトで共有される不連続変数です。 これらは共有されているため、クラス定義の外部で定義および初期化する必要があります。 詳細については、クラスに関するページを参照してください。

extern 宣言

C++ プログラムには、複数のコンパイル単位が含まれる場合があります。 個別のコンパイル単位で定義されたエンティティを宣言するには、extern キーワードを使用します。 コンパイラに対して宣言内の情報は十分です。 しかし、リンク手順でエンティティの定義が見つからない場合は、リンカーからエラーが発生します。

このセクションの内容

ストレージ クラス
const
constexpr
extern
初期化子
エイリアスと typedef
using 宣言
volatile
decltype
C++ の属性

関連項目

基本的な概念