龙空技术网

C++ 的9种作用域(scope)

小智雅汇 695

前言:

眼前我们对“语句块作用域”大概比较讲究,朋友们都需要剖析一些“语句块作用域”的相关内容。那么小编也在网络上收集了一些对于“语句块作用域””的相关知识,希望朋友们能喜欢,大家快快来了解一下吧!

Each identifier that appears in a C++ program is visible (that is, may be used) only in some possibly discontiguous portion of the source code called its scope.

出现在C++程序中的每个标识符仅在源代码中称为其作用域的某些可能不连续的部分中可见(也就是说,可以使用)。

Within a scope, an identifier may designate more than one entity only if the entities are in different name spaces.

在一个范围内,只有当实体位于不同的名称空间中时,标识符才可以指定多个实体。

C++ has four kinds of scopes:

① block scope and nested block scope

② file scope

③ function scope

④ function prototype(or parameter) scope

5 Namespace scope

6 Class scope

7 Enumeration scope

8 Template parameter scope

9 Point of declaration

1 Block scope

The potential scope of a name declared in a block (compound statement) begins at the point of declaration and ends at the end of the block. Actual scope is the same as potential scope unless an identical name is declared in a nested block, in which case the potential scope of the name in the nested block is excluded from the actual scope of the name in the enclosing block.

在块(复合语句)中声明的名称的潜在作用域从声明点开始(C and C++ use one-pass compilers),到块的末尾结束。实际作用域与潜在作用域相同,除非在嵌套块中声明了相同的名称,在这种情况下,嵌套块中名称的潜在作用域将从封闭块中名称的实际作用域中排除。

The scope of any identifier declared inside a compound statement, including function bodies, or in any expression, declaration, or statement appearing in if, switch, for, while, or do-while statement (since C99), or within the parameter list of a function definition begins at the point of declaration and ends at the end of the block or statement in which it was declared.

在复合语句(包括函数体)中声明的任何标识符的范围,或在if、switch、for、while或do-while语句(自C99起)中出现的任何表达式、声明或语句中,或在函数定义的参数列表中声明的任何标识符的范围,从声明点开始,到声明它的块或语句的末尾结束。

void f(int n)  // scope of the function parameter 'n' begins{         // the body of the function begins    ++n;   // 'n' is in scope and refers to the function parameter    // int n = 2; // error: cannot redeclare identifier in the same scope    for(int n = 0; n<10; ++n) { // scope of loop-local 'n' begins        printf("%d\n", n); // prints 0 1 2 3 4 5 6 7 8 9    } // scope of the loop-local 'n' ends    // the function parameter 'n' is back in scope    printf("%d\n", n); // prints the value of the parameter} // scope of function parameter 'n' endsint a = n; // Error: name 'n' is not in scopeint main() {    int i = 0; // scope of outer i begins    ++i; // outer i is in scope    {        int i = 1; // scope of inner i begins,                   // scope of outer i pauses        i = 42; // inner i is in scope    } // block ends, scope of inner i ends,      // scope of outer i resumes} // block ends, scope of outer i ends//int j = i; // error: i is not in scope

Block-scope variables have no linkage and automatic storage duration by default. Note that storage duration for non-VLA local variables begins when the block is entered, but until the declaration is seen, the variable is not in scope and cannot be accessed.

默认情况下,块作用域变量没有链接和自动存储持续时间。请注意,非VLA(variant length arrays)局部变量的存储持续时间从输入块时开始,但在看到声明之前,该变量不在范围内,无法访问。

If two different entities named by the same identifier are in scope at the same time, and they belong to the same name space, the scopes are nested (no other form of scope overlap is allowed), which is called nested block scopes, and the declaration that appears in the inner scope hides the declaration that appears in the outer scope:

如果由同一标识符命名的两个不同实体同时在作用域中,并且它们属于相同的名称空间,则作用域是嵌套的(不允许其他形式的作用域重叠),称为嵌套的块作用域,并且显示在内部作用域中的声明隐藏了显示在外部作用域中的声明:

// The name space here is ordinary identifiers.int a;   // file scope of name a begins herevoid f(void){    int a = 1; // the block scope of the name a begins here; hides file-scope a    {      int a = 2;         // the scope of the inner a begins here, outer a is hidden      printf("%d\n", a); // inner a is in scope, prints 2    }                    // the block scope of the inner a ends here    printf("%d\n", a);   // the outer a is in scope, prints 1}                        // the scope of the outer a ends here void g(int a);   // name a has function prototype scope; hides file-scope a
2 File scope

The scope of any identifier declared outside of any block or parameter list begins at the point of declaration and ends at the end of the translation unit.

在任何块或参数列表之外声明的任何标识符的范围从声明点开始,到翻译单元的末尾结束。

int i; // scope of i beginsstatic int g(int a) { return a; } // scope of g begins (note, "a" has block scope)int main(void){    i = g(2); // i and g are in scope}

File-scope identifiers have external linkage and static storage duration by default.

默认情况下,文件作用域标识符具有外部链接和静态存储持续时间。

3 Function scope

A label (and only a label) declared inside a function is in scope everywhere in that function, in all nested blocks, before and after its own declaration. Note: a label is declared implicitly, by using an otherwise unused identifier before the colon character before any statement.

在函数中声明的标签(且仅为标签)在该函数的任何位置、所有嵌套块中、在其自身声明之前和之后都在作用域中。注意:标签是通过在任何语句之前的冒号字符之前使用未使用的标识符隐式声明的。

void f(){   {          goto label; // label in scope even though declared laterlabel:;   }   goto label; // label ignores block scope} void g(){    goto label; // error: label not in scope in g()}
4 Function prototype scope(Function parameter scope)

The scope of a name introduced in the parameter list of a function declaration that is not a definition ends at the end of the function declarator.

在非定义的函数声明的参数列表中引入的名称的范围在函数声明器的末尾结束。

int f(int n,      int a[n]); // n is in scope and refers to the first parameter

Note that if there are multiple or nested declarators in the declaration, the scope ends at the end of the nearest enclosing function declarator:

请注意,如果声明中有多个或嵌套的声明符,则范围将在最近的封闭函数声明符的末尾结束:

void f ( // function name 'f' is at file scope long double f,            // the identifier 'f' is now in scope, file-scope 'f' is hidden char (**a)[10 * sizeof f] // 'f' refers to the first parameter, which is in scope); enum{ n = 3 };int (*(*g)(int n))[n]; // the scope of the function parameter 'n'                       // ends at the end of its function declarator                       // in the array declarator, global n is in scope// (this declares a pointer to function returning a pointer to an array of 3 int)
5 Namespace scope

The potential scope of a name declared in a namespace begins at the point of declaration and includes the rest of the namespace and all namespace definitions with an identical namespace name that follow, plus, for any using-directive that introduced this name or its entire namespace into another scope, the rest of that scope.

在名称空间中声明的名称的潜在作用域从声明点开始,包括名称空间的其余部分以及后面具有相同名称空间名称的所有名称空间定义,此外,对于将此名称或其整个名称空间引入另一个作用域的任何using指令,还包括该作用域的其余部分。

The top-level scope of a translation unit ("file scope" or "global scope") is also a namespace and is properly called "global namespace scope". The potential scope of a name declared in the global namespace scope begins at the point of declaration and ends at the end of the translation unit.

翻译单元的顶级作用域(“文件作用域”或“全局作用域”)也是一个名称空间,正确地称为“全局名称空间作用域”。在全局命名空间范围中声明的名称的潜在范围从声明点开始,到翻译单元的末尾结束。

The potential scope of a name declared in an unnamed namespace or in an inline namespace includes the potential scope that name would have if it were declared in the enclosing namespace.

在未命名命名空间或内联命名空间中声明的名称的潜在作用域包括该名称在封闭命名空间中声明时所具有的潜在作用域。

namespace N { // scope of N begins (as a member of global namespace)    int i; // scope of i begins    int g(int a) { return a; } // scope of g begins    int j(); // scope of j begins    void q(); // scope of q begins    namespace {        int x; // scope of x begins    } // scope of x continues (member of unnamed namespace)    inline namespace inl { // scope of inl begins        int y; // scope of y begins    } // scope of y continues (member of inline namespace)} // scopes of i, g, j, q, inl, x, and y pause namespace {    int l = 1; // scope of l begins} // scope of l continues (member of unnamed namespace) namespace N { // scopes of i, g, j, q, inl, x, and y resume    int g(char a) { // overloads N::g(int)        return l + a; // l from unnamed namespace is in scope    }//  int i; // error: duplicate definition (i is already in scope)    int j(); // OK: duplicate function declaration is allowed    int j() { // OK: definition of the earlier-declared N::j()        return g(i); // calls N::g(int)    }//  int q(); // error: q is already in scope with a different return type} // scopes of i, g, j, q, inl, x, and y pause int main() {    using namespace N; // scopes of i, g, j, q, inl, x, and y resume    i = 1; // N::i is in scope    x = 1; // N::(anonymous)::x is in scope    y = 1; // N::inl::y is in scope    inl::y = 2; // N::inl is also in scope} // scopes of i, g, j, q, inl, x, and y end

The name may also be visible in translation units that have imported the current translation unit.

该名称也可能在已导入当前翻译单元的翻译单元中可见。

6 Class scope

The potential scope of a name declared in a class begins at the point of declaration and includes the rest of the class body, all the derived classes bodies, the function bodies (even if defined outside the class definition or before the declaration of the name), function default arguments, function exception specifications, in-class brace-or-equal initializers, and all these things in nested classes, recursively.

在类中声明的名称的潜在作用域从声明点开始,包括类主体的其余部分、所有派生类主体、函数主体(即使在类定义之外或名称声明之前定义)、函数默认参数、函数异常规范、类内大括号或相等的初始值设定项,所有这些都是在嵌套类中递归进行的。

struct X {    int f(int a = n) { // n is in scope in function default argument        return a * n;  // n is in scope in function body    }    using r = int;    r g();    int i = n * 2; // n is in scope in initializer//  int x[n]; // error: n is not in scope in class body    static const int n = 1; // scope of n begins    int x[n]; // OK: n is now in scope in class body}; // scope of n pauses struct Y: X { // scope of n resumes    int y[n]; // n is in scope}; // scope of n ends //r X::g() {     // error: r is not in scope outside out-of-class function bodyauto X::g()->r { // OK: trailing return type r is in scope    return n;    // n is in scope in out-of-class function body}

If a name is used in a class body before it is declared, and another declaration for that name is in scope, the program is ill-formed, no diagnostic required.

如果在声明前在类主体中使用了一个名称,并且该名称的另一个声明在作用域中,则程序的格式不正确,不需要进行诊断。

typedef int c; // ::cenum { i = 1 }; // ::i class X {//  char v[i]; // error: at this point, i refers to ::i               // but there is also X::i    int f() {         return sizeof(c); // OK: X::c is in scope in member function    }    enum { i = 2 }; // X::i    char c;         // X::c    char w[i]; // OK: i refers to X::i now}; // scope of outer i resumes typedef char* T;struct Y {//  T a; // error: at this point, T refers to ::T         // but there is also Y::T    typedef long T;    T b;};

Names of class members can be used in the following contexts:

类成员的名称可以在以下上下文中使用:

in its own class scope or in the class scope of a derived class;

在其自身的类范围内或派生类的类范围内;

after the operator applied to an expression of the type of its class or a class derived from it;

运算符应用于其类类型的表达式或从其派生的类之后;

after the -> operator applied to an expression of the type of pointer to its class or pointers to a class derived from it;

在->运算符应用于指向其类的指针类型的表达式或指向从其派生的类的指针之后;

after the :: operator applied to the name of its class or the name of a class derived from it.

在::运算符应用于其类的名称或从其派生的类的名称之后。

7 Enumeration scope

The potential scope of an enumerator of an unscoped enumeration begins at the point of declaration and ends at the end of the enclosing scope.

非作用域枚举的枚举数的潜在作用域开始于声明点,结束于封闭作用域的末尾。

The potential scope of an enumerator of a scoped enumeration begins at the point of declaration and ends at the end of the enum specifier.

作用域枚举的枚举数的潜在作用域开始于声明点,结束于枚举说明符的末尾。

enum e1_t { // unscoped enumeration    A,    B = A * 2 // A is in scope}; // scopes of A and B continue enum class e2_t { // scoped enumeration    SA,    SB = SA * 2 // SA is in scope}; // scopes of SA and SB end e1_t e1 = B; // OK: B is in scope//e2_t e2 = SB; // error: SB is not in scopee2_t e2 = e2_t::SB; // OK
8 Template parameter scope

The potential scope of a template parameter name begins at the point of declaration and ends at the end of the smallest template declaration in which it was introduced. In particular, a template parameter can be used in the declarations of subsequent template parameters and in the specifications of base classes, but can't be used in the declarations of the preceding template parameters.

模板参数名称的潜在作用域开始于声明点,结束于引入它的最小模板声明的末尾。特别是,模板参数可以在后续模板参数的声明和基类的规范中使用,但不能在之前模板参数的声明中使用。

template<    typename T, // scope of T begins    T* p,       // T is in scope    class U = T // T is in scope>class X: public std::vector<T> // T is in scope{    T f(); // T is in scope}; // scopes of T and U end

The potential scope of the name of the parameter of a template template parameter is the smallest template parameter list in which that name appears.

模板模板参数的参数名称的潜在范围是该名称所在的最小模板参数列表。

template<    template< // template template parameter        typename Y,    // scope of Y begins        typename G = Y // Y is in scope    > // scopes of Y and G end    class T,//  typename U = Y // error: Y is not in scope    typename U>class X {}; // scopes of T and U end

Similar to other nested scopes, the name of a template parameter hides the same name from the enclosing scope for the duration of its own.

与其他嵌套作用域类似,模板参数的名称在其自身的持续时间内对封闭作用域隐藏相同的名称。

typedef int N;template<    N X, // ::N is in scope    typename N, // scope of N begins, scope of ::N pauses    template<N Y> class T // N is in scope>struct A; // scope of N ends, scope of ::N resumes
9 Point of declaration

The scope of structure, union, and enumeration tags begins immediately after the appearance of the tag in a type specifier that declares the tag.

结构、联合和枚举标记的范围在标记出现在声明标记的类型说明符中后立即开始。

struct Node {   struct Node* next; // Node is in scope and refers to this struct};

The scope of enumeration constant begins immediately after the appearance of its defining enumerator in an enumerator list.

枚举常量的范围在其定义枚举器出现在枚举器列表中后立即开始。

enum { x = 12 };{    enum { x = x + 1, // new x is not in scope until the comma, x is initialized to 13           y = x + 1  // the new enumerator x is now in scope, y is initialized to 14         };}

The scope of any other identifier begins just after the end of its declarator and before the initializer, if any:

任何其他标识符的作用域开始于其声明符的末尾之后和初始值设定项之前(如果有):

int x = 2; // scope of the first 'x' begins{    int x[x]; // scope of the newly declared x begins after the declarator (x[x]).              // Within the declarator, the outer 'x' is still in scope.              // This declares a VLA array of 2 int.}
unsigned char x = 32; // scope of the outer 'x' begins{    unsigned char x = x;            // scope of the inner 'x' begins before the initializer (= x)            // this does not initialize the inner 'x' with the value 32,             // this initializes the inner 'x' with its own, indeterminate, value} unsigned long factorial(unsigned long n)// declarator ends, 'factorial' is in scope from this point{   return n<2 ? 1 : n*factorial(n-1); // recursive call}

As a special case, the scope of a type name that is not a declaration of an identifier is considered to begin just after the place within the type name where the identifier would appear were it not omitted.

作为一种特殊情况,如果不省略标识符,则认为不是标识符声明的类型名称的作用域就开始于类型名称中标识符出现的位置之后。

ref

标签: #语句块作用域 #c语言scope