首页 > 其他分享 >【cplusplus教程翻译】名字可见性(Name visibility)

【cplusplus教程翻译】名字可见性(Name visibility)

时间:2023-05-18 21:57:01浏览次数:50  
标签:Name int cplusplus namespace visibility 名称 命名 using 变量

作用域(Scopes)

命名实体,如变量、函数和复合类型,在C++中使用之前需要声明。程序中发生此声明的点会影响其可见性:
在任何块外部声明的实体都具有全局作用域,这意味着其名称在代码中的任何位置都是有效的。而在块内声明的实体,如函数或选择性语句,具有块作用域,并且只能在声明它的特定块内可见,而不能在块外可见。
具有块作用域的变量称为局部变量。
例如,在函数体中声明的变量是一个局部变量,它一直延伸到函数的末尾(即,直到关闭函数定义的大括号),但不在函数的外部:

int foo;        // global variable
int some_function ()
{
  int bar;      // local variable
  bar = 0;
}
int other_function ()
{
  foo = 1;  // ok: foo is a global variable
  bar = 2;  // wrong: bar is not visible from this function
}

在每个作用域中,一个名称只能表示一个实体。例如,在同一作用域内不能有两个具有相同名称的变量:

int some_function ()
{
  int x;
  x = 0;
  double x;   // wrong: name already used in this scope
  x = 0.0;
}

具有块范围的图元的可见性一直延伸到块的末尾,包括内部块。然而,内部块,因为它是一个不同的块,可以重新利用外部范围中存在的名称来指代不同的实体;在这种情况下,名称将仅引用内部块中的不同实体,从而隐藏其在外部命名的实体。在它之外,它仍将引用原始实体。例如:

// inner block scopes
#include <iostream>
using namespace std;

int main () {
  int x = 10;
  int y = 20;
  {
    int x;   // ok, inner scope.
    x = 50;  // sets value to inner x
    y = 50;  // sets value to (outer) y
    cout << "inner block:\n";
    cout << "x: " << x << '\n';
    cout << "y: " << y << '\n';
  }
  cout << "outer block:\n";
  cout << "x: " << x << '\n';
  cout << "y: " << y << '\n';
  return 0;
}

请注意,y在内部块中没有被隐藏,因此访问y仍然访问外部变量。
在引入块的声明中声明的变量,例如在循环和条件中声明的函数参数和变量(例如在for或if上声明的变量),对于它们引入的块是本地的。

命名空间(namespace)

在特定的作用域中,只能存在一个具有特定名称的实体。对于局部名称来说,这很少是一个问题,因为块往往相对较短,并且名称在其中有特定的用途,例如命名计数器变量、参数等。
但非本地名称带来了更多名称冲突的可能性,特别是考虑到库可能声明许多函数、类型和变量,它们本质上都不是本地的,而且其中一些非常通用。
命名空间允许我们将原本具有全局作用域的命名实体分组到更窄的作用域中,从而赋予它们命名空间作用域。这允许将程序的元素组织到由名称引用的不同逻辑范围中。
声明命名空间的语法是

namespace identifier
{
  named_entities
}

其中,identifier是任何有效的标识符,named_entities是命名空间中包含的一组变量、类型和函数。例如:

namespace identifier
{
  int a, b;
}

在这种情况下,变量a和b是在名为myNamespace的命名空间中声明的普通变量。
这些变量通常可以使用其标识符(a或b)从其命名空间内访问,但如果从myNamespace命名空间外访问,则必须使用scope运算符::对其进行适当限定。例如,要从myNamespace外部访问以前的变量,语法如下:

myNamespace::a
myNamespace::b

命名空间对于避免名称冲突特别有用。例如:

// namespaces
#include <iostream>
using namespace std;

namespace foo
{
  int value() { return 5; }
}

namespace bar
{
  const double pi = 3.1416;
  double value() { return 2*pi; }
}

int main () {
  cout << foo::value() << '\n';
  cout << bar::value() << '\n';
  cout << bar::pi << '\n';
  return 0;
}

在这种情况下,有两个函数具有相同的名称:value。一个在名称空间foo中定义,另一个在bar中定义。由于使用了名称空间,因此不会发生重新定义错误。还要注意,在main中再次访问pi时,如何以非限定的方式从名称空间bar中访问pi(就像pi一样),但这里需要将其限定为bar::pi
命名空间可以拆分:代码的两段可以在同一个命名空间中声明:

namespace foo { int a; }
namespace bar { int b; }
namespace foo { int c; }

这声明了三个变量:a和c在名称空间foo中,而b在名称空间bar中。命名空间甚至可以扩展到不同的翻译单元(即,扩展到源代码的不同文件)。

using

关键字using将名称引入当前声明性区域(如块),从而避免了对名称进行限定的需要。例如:

// using
#include <iostream>
using namespace std;

namespace first
{
  int x = 5;
  int y = 10;
}

namespace second
{
  double x = 3.1416;
  double y = 2.7183;
}

int main () {
  using first::x;
  using second::y;
  cout << x << '\n';
  cout << y << '\n';
  cout << first::y << '\n';
  cout << second::x << '\n';
  return 0;
}

请注意,变量x(没有任何名称限定符)主要指第一个::x,而y指第二个::y,正如using声明所指定的那样。变量first::y和second::x仍然可以访问,但需要完全限定的名称。
关键字using也可以用作引入整个命名空间的指令:

// using
#include <iostream>
using namespace std;

namespace first
{
  int x = 5;
  int y = 10;
}

namespace second
{
  double x = 3.1416;
  double y = 2.7183;
}

int main () {
  using namespace first;
  cout << x << '\n';
  cout << y << '\n';
  cout << second::x << '\n';
  cout << second::y << '\n';
  return 0;
}

在这种情况下,通过声明命名空间first,可以直接使用first命名空间中的变量x和y。
using和using namespace仅在声明它们的同一块中有效,或者如果它们直接在全局范围中使用,则在整个源代码文件中有效。例如,可以先使用一个命名空间的对象,然后通过将代码拆分为不同的块来使用另一个命名空间中的对象:

// using namespace example
#include <iostream>
using namespace std;

namespace first
{
  int x = 5;
}

namespace second
{
  double x = 3.1416;
}

int main () {
  {
    using namespace first;
    cout << x << '\n';
  }
  {
    using namespace second;
    cout << x << '\n';
  }
  return 0;
}

命名空间别名

现有名称空间可以使用新名称进行别名,语法如下:

namespace new_name = current_name;

std命名空间

标准C++库的所有实体(变量、类型、常量和函数)都在std命名空间中声明。事实上,这些教程中的大多数示例都包括以下行:

using namespace std;

这引入了std命名空间的所有名称在代码中的直接可见性。在这些教程中这样做是为了便于理解并缩短示例的长度,但许多程序员更喜欢对程序中使用的标准库的每个元素进行限定。例如,而不是:

cout << "Hello world!";

通常是这样使用的

std::cout << "Hello world!";

std命名空间中的元素是通过using声明引入的,还是在每次使用时都是完全限定的,都不会以任何方式改变生成程序的行为或效率。这主要是一个风格偏好的问题,尽管对于混合库的项目,明确的限定往往是首选。

存储类别

具有全局或命名空间作用域的变量的存储是为程序的整个持续时间分配的。这被称为静态存储,它与局部变量(在块中声明的变量)的存储形成对比。这些使用所谓的自动存储。局部变量的内存仅在声明局部变量的块期间可用;之后,相同的内存可以用于某些其他函数的局部变量,或者以其他方式使用。
但具有静态存储的变量和具有自动存储的变量之间还有另一个实质性区别:
-未显式初始化的具有静态存储的变量(如全局变量)会自动初始化为零。
-未明确初始化的具有自动存储的变量(如局部变量)未初始化,因此具有未确定的值。

// static vs automatic storage
#include <iostream>
using namespace std;

int x;

int main ()
{
  int y;
  cout << x << '\n';
  cout << y << '\n';
  return 0;
}

实际输出可能会有所不同,但只有x的值才能保证为零。y实际上可以包含几乎任何值(包括零)。

标签:Name,int,cplusplus,namespace,visibility,名称,命名,using,变量
From: https://www.cnblogs.com/xiaoweing/p/17413134.html

相关文章

  • RocketMQ源码(三):服务端NameSrv启动流程
    有关Namesrv的概念及功能,详见RocketMQ(三):架构设计中技术架构组成namesrv,这里不再赘述。RocketMQ中Namesrv启动入口:org.apache.rocketmq.namesrv.NamesrvStartup。Namesrv启动,NamesrvStartup#main0()核心伪代码:1publicstaticNamesrvControllermain0(String[......
  • ModuleNotFoundError: No module named 'MySQLdb'
    想用FastApi搞点东西,之前没怎么接触过python,根据pyloong大佬的文章https://pyloong.github.io/pythonic-project-guidelines/practices/web/#36-fastapi创建demo,到运行是出现了这个错误:ModuleNotFoundError:Nomodulenamed'MySQLdb'。然后各种chatGPT,bing,google,找到的都是要我......
  • el-table的header-row-class-name或者row-class-name不生效的解决办法?
    思路如果使用的node脚手架,你的style标签长这样:<stylescoped></style>,那么只需要在给header-row-class-name或者row-class-name指定的css类上做个样式穿透。解决办法如:<el-table row-class-name="table-row-class"></el-table><stylescoped> /deep/.table-row-clas......
  • k8s删除命名空间namespace一直显示Terminating问题处理
    转载自:https://huaweicloud.csdn.net/638db195dacf622b8df8c5f7.html============= 1、问题现象假设我们的现在要删除的namespace是dev,执行如下命令进行删除:执行如下命令查看namespace删除情况:可以看到删除状态显示Terminating,而且会一直持续这个状态。并且用:kubectldeleten......
  • namespace,pv 一直Terminating状态处理
    1,namespace  Terminating状态处理在k8s集群中进行测试删除namespace是经常的事件,而为了方便操作,一般都是直接对整个名称空间进行删除操作。$kubectlgetnsqasimNAMESTATUSAGEqasimTerminating24d 调用接口删除开启一个代理终端$kubectlpro......
  • PHP命名空间(Namespace)初探
    探完闭包[查看],再探命名空间。对于命名空间,官方文档已经说得很详细[查看],我在这里做了一下实践和总结。命名空间一个最明确的目的就是解决重名问题,PHP中不允许两个函数或者类出现相同的名字,否则会产生一个致命的错误。这种情况下只要避免命名重复就可以解决,最常见的一种做法是约定......
  • ECMAScript6新特性【函数的扩展(函数参数的默认值、箭头函数、rest 参数、name 属性)
    ......
  • 多次重新初始化hadoop namenode -format后,DataNode或NameNode没有启动
    多次重新初始化hadoopnamenode-format后,DataNode或NameNode没有启动在搭建完hadoop集群后,需要对主节点进行初始化(格式化)其本质是清理和做一些准备工作,因为此时的HDFS在物理上还是存在的。而且主节点格式化操作只能进行一次。当我们不小心多次初始化,会导致启动hadoop集群时,主......
  • Vue项目报错: Component name “xxx“ should always be multi-word vue/multi-word-co
    报错的意思是组件名应该始终是多单词,不应该以单个单词命名组件解决办法1:修改组件名称:例如当前的登陆组件名是login.vue修改成LoginName.vue,组件名需要以驼峰式命名至少两个单词,不一定都得是LoginName.vue可以是NameLogin.vue也可以是LoginNiu.vue总之就是以驼峰式命名......
  • Component name "tag" should always be multi-word.
    Componentname"tag"shouldalwaysbemulti-word.这种错误通常是由于编码规范或代码风格指南中的命名规范没有被遵守所导致的。vue中,我命名一个组件叫tag好像不符合规范,应该怎么命名?在Vue中,如果你要命名一个组件,可以采用驼峰式命名法,即使用多个单词组成的名称,每个单词的首......