スコープ (C)

クラス、関数、変数などのプログラム要素を宣言する場合、その名前は "表示" され、プログラムの特定の部分でのみ使用できます。 名前が表示されるコンテキストは、そのスコープと呼ばれます。 たとえば、関数内で変数 x を宣言すると、x は、その関数本体内でのみ表示されます。 ローカル スコープがあります。 プログラム内に同じ名前の他の変数がある場合があります。スコープが異なる限り、1 つの定義規則に違反し、エラーは発生しません。

自動非静的変数の場合、スコープによって、プログラム メモリ内でいつ作成および破棄されるのかも決定されます。

スコープには次の 6 種類があります。

  • グローバル スコープ グローバル名は、クラス、関数、または名前空間の外部で宣言された名前です。 ただし、C++ では、これらの名前も暗黙的なグローバル名前空間と一緒に存在します。 グローバル名のスコープは、宣言の時点から、宣言されるファイルの末尾まで拡張されます。 グローバル名の場合、可視性はリンケージの規則によっても制御され、プログラム内の他のファイルで名前が表示されるかどうかを判断します。

  • 名前空間スコープ クラスまたは列挙型の定義または関数ブロックの外部にある名前空間内で宣言された名前は、宣言のポイントから名前空間の末尾まで表示されます。 名前空間は、異なるファイル間で複数のブロックで定義できます。

  • ローカル スコープ 関数またはラムダ内で宣言された名前 (パラメーター名を含む) には、ローカル スコープがあります。 多くの場合、"ローカル" と呼ばれます。 これらは、宣言の時点から関数またはラムダ本体の末尾にのみ表示されます。 ローカル スコープは、この記事で後で説明するブロック スコープの一種です。

  • クラス スコープ クラス メンバーの名前には、宣言のポイントに関係なくクラス定義全体に拡張されるクラス スコープがあります。 クラス メンバーのアクセシビリティは、publicprivate、および protected キーワードによって、さらに制御されます。 パブリック メンバーまたは保護されたメンバーには、メンバー選択演算子 (. または ->) またはポインターからメンバーへのポインター演算子 (.* または ->*) を使用した場合にのみアクセスできます。

  • ステートメント スコープforifwhile、または switch ステートメントで宣言された名前は、ステートメント ブロックの末尾まで表示されます。

  • 関数スコープ A ラベル には関数スコープがあります。つまり、宣言ポイントの前でも関数本体全体で表示されます。 関数スコープを使用すると、cleanup ラベルが宣言される前に goto cleanup のようなステートメントを記述できます。

名前の隠ぺい

囲まれたブロック内で名前を宣言すると、その名前が非表示になります。 次の図では、内側のブロックで i が再宣言されています。そのため、外側のブロック スコープでは i に関連付けられた変数が隠し変数になります。

Diagram that shows block scope name hiding.
ブロック スコープおよび名前の非表示

このプログラムの出力を次の図に示します。

i = 0
i = 7
j = 9
i = 0

Note

szWhat 引数は、この関数のスコープ内にあると見なされます。 したがって、この関数の外側のブロックで宣言されたものとして処理されます。

クラス名の非表示

関数、オブジェクト、変数、または列挙子を同じスコープ内で宣言することで、クラス名を非表示にできます。 ただし、class キーワードを先頭に付加すれば、非表示にしたクラス名にアクセスできます。

// hiding_class_names.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;

// Declare class Account at global scope.
class Account
{
public:
    Account( double InitialBalance )
        { balance = InitialBalance; }
    double GetBalance()
        { return balance; }
private:
    double balance;
};

double Account = 15.37;            // Hides class name Account

int main()
{
    class Account Checking( Account ); // Qualifies Account as
                                       //  class name

    cout << "Opening account with a balance of: "
         << Checking.GetBalance() << "\n";
}
//Output: Opening account with a balance of: 15.37

Note

クラス名 (Account) を呼び出すときは、ファイル スコープ変数 Account と区別するため、class キーワードを使用する必要があります。 スコープ解決演算子 (::) の左側がクラス名の場合は、この規則が適用されません。 スコープ解決演算子の左側の名前は、常にクラス名と見なされます。

次に、class キーワードを使用して、Account 型のオブジェクトへのポインターを宣言する方法を例示します。

class Account *Checking = new class Account( Account );

上記のステートメントで、初期化子の (かっこで囲まれた) Account はグローバル スコープで double 型です。

Note

この例のように、識別子名を再使用するのは適切なプログラミング方法ではありません。

クラス オブジェクトの宣言と初期化については、「クラス、構造体、共用体」を参照してください。 フリー ストア演算子 new および delete の使用方法については、「new および delete 演算子」を参照してください。

グローバル スコープでの名前の非表示

ブロック スコープで同じ名前で明示的に宣言して、グローバル スコープを持つ名前を非表示にすることができます。 ただし、スコープ解決演算子 (::) を使用して、ファイル スコープ名にアクセスできます。

#include <iostream>

int i = 7;   // i has global scope, outside all blocks
using namespace std;

int main( int argc, char *argv[] ) {
   int i = 5;   // i has block scope, hides i at global scope
   cout << "Block-scoped i has the value: " << i << "\n";
   cout << "Global-scoped i has the value: " << ::i << "\n";
}
Block-scoped i has the value: 5
Global-scoped i has the value: 7

関連項目

基本的な概念