C++中的作用域与生命周期



Pascal之父Nicklaus Wirth曾经提出一个公式,展示出了程序的本质:程序=算法+数据结构。后人又给出一个公式与之遥相呼应:软件=程序+文档。这两个公式可以简洁明了的为我们展示程序和软件的组成。

程序的运行过程可以理解为算法对数据的加工过程,程序的运行的结果,就是算法加工数据产生的结果数据。算法描述的是对数据加工的步骤,对应于程序中的函数。数据结构描述的是数据在计算机中的组织结构,对应于程序中的数据类型。程序中数据对应的就是无处不在变量。对于我们编程人员,面对的无非就是函数,数据类型和变量。因此,C++谈及作用域与生命周期针对的就是这三大程序的组成要素:函数、数据类型和变量。下面将一一讲述。


1.作用域与生命周期的区别

作用域与生命周期是完全两个不同的概念。在英文中个,作用域用“scope”表示,生命周期则用“duration”表示。作用域是一个静态概念,只在编译源程序的时候用到。一个标识符的作用域指在源文件中该标识符能够独立地合法出现的区域。生命周期则是一个运行时(Runtime)概念,它是指一个变量在整个程序从载入到结束运行的过程中存在的时间周期。由于函数和数据类型是静态的概念,它们没有生命周期的说法,它们从编译时、程序的运行到结束整个过程是一直存在的。

C++中作用域的级别主要有文件域(全局作用域)、命名空间域、类域、函数作用域和代码块作用域(局部域)。

2.函数的作用域

函数分为类的成员函数和全局函数。

类的成员函数:

- 作用域:类域。

- 生命周期:无(程序运行期一直存在)。

- 引用方法:其他文件中要使用必须用点操作符(.)或作用域运算符(::)来引用。

- 内存分布:代码区。

- 注意:类成员函数可以定义在类体内,即定义在头文件,当类被不同源文件包含时不会报重定义的错误,因为作用域被限制在类体中。

举例如下:

//main.cpp
class test
{
private:
    int i;
public:
    void show()
    {
        cout<<"i:"<<i<<endl;
    }
};
int main(int argc,char* argv[])
{
    test t;
    t.show()
}

全局函数:

- 作用域:文件域(全局作用域)。

- 生命周期:无(程序运行期一直存在)。

- 引用方法:其他文件中要先进行函数原型声明,再使用。

- 内存分布:代码区。

- 注意:如果在两个源文件中定义了同名的全局函数,连接时会出现重定义错误。

举例如下:

//function.cpp
void printHello()
{
    cout<<"hello world"<<endl;
}

//main.cpp
void printHello();
int main(int argc,char* argv[])
{
    printHello();
}

3.数据类型的作用域

C++中的数据类类型分为基本数据类型和非基本数据类型,非基本数据类型中又分为复合数据类型和构造数据类型。关于C++中的数据类型,详见本人另一篇blog: C++数据类型.

基本数据类型:

基本数据类型包括整型(int)、实型(float和double)、字符型(char)、布尔型(bool)和无值型(void)。

  • 作用域:文件域(全局作用域)。
  • 生命周期:无(程序运行期一直存在)。
  • 引用方法:无需申明,直接使用。
  • 内存分布:代码区。

复合数据类型:

复合数据类型包括:数组(type[])、指针(type*)、引用(type&)、枚举(enum)。

如果复合数据类型是构造数据类型参与的复合,其作用域与构造数据类型一致。enum枚举类型的作用域与构造类型相同。

构造数据类型:

- 作用域:类型定义所在的域,其他文件不可见。

- 生命周期:无(程序运行期一直存在)。

- 引用方法:其他文件中要先进行定义,再通过作用域运算符进行使用。

- 内存分布:代码区。

- 注意:只要文件不互相包含,如果在两个源文件中定义了同名的构造,不会出现重定义错误,因为数据类型不具有外部连接性。

举例如下:

//main.cpp
namespace dd{
   class test
   {
   private:
    int i;
   public:
    void show()
    {
        cout<<"i:"<<i<<endl;
    }
   };
}
using namespace dd;//引用命名空间域中的构造类型test,否则无法使用
int main(int argc,char* argv[])
{
    test t;
    t.show();
}

4.变量的作用域与生命周期

我们面对的变量主要分为全局变量、全局静态变量、局部变量和局部静态变量。下面一一讲述他们的作用域与生命周期。

全局变量:

- 作用域:全局作用域(全局变量只需在一个源文件中定义,就可以作用于所有的源文件);

- 生命周期:程序运行期一直存在;

- 引用方法:其他文件中要使用必须用extern 关键字声明要引用的全局变量。;

- 内存分布:全局/静态存储区;

- 注意:如果在两个文件中都定义了相同名字的全局变量,连接出错:变量重定义。

举例如下:

//define.cpp
int g_iValue = 1;  

//main.cpp
extern int g_iValue;  

int main()
{
    cout << g_iValue;
    return 0;
}  

全局静态变量:

- 作用域:文件作用域(只在被定义的文件中可见);

- 生命周期:程序运行期一直存在;

- 内存分布:全局/静态存储区;

- 定义方法:static关键字,const 关键字;

- 注意:只要文件不互相包含,在两个不同的文件中是可以定义完全相同的两个静态变量的,它们是两个完全不同的变量。

举例如下:

//define.cpp
const int iValue=8;   

//main.cpp
int iValue;
static const int iValue_2;
static int iValue_3;
int main(int argc,char* argv[])
{
    cout<<"iValue:"<<iValue<<endl;
    return 0;
}

局部变量:

- 作用域:局部作用域(只在局部作用域中可见,如函数域,代码块域);

- 生命周期:程序运行出局部作用域即被销毁;

- 内存分布:栈区;

- 注意:auto指示符标示。

举例如下:

void print()
{
    int a=0;
    cout<<a<<endl;
}

局部静态变量:

- 作用域:局部作用域(只在局部作用域中可见);

- 生命周期:程序运行期一直存在;

- 内存分布:全局静态存储区;

- 定义方法:局部作用域用中用static定义;

- 注意:只被初始化一次,多线程中需加锁保护。

举例如下:

void function()
{
    static int iREFCounter = 0;
}  

5.扩展知识点

1.变量存储说明符

C语言中提供了存储说明符auto,register,extern,static说明的四种存储类别。四种存储类别说明符有两种存储期:自动存储期和静态存储期。其中auto和register对应自动存储期。具有自动存储期的变量在进入声明该变量的程序块是被建立,它在该程序块活动时存在,退出该程序块时撤销。静态存储期从程序载入运行到程序结束一直存在。

2.static使用建议

(1)若全局变量仅在单个C文件中访问,则可以将这个变量修改为静态全局变量,以降低模块间的耦合度;

(2)若全局变量仅由单个函数访问,则可以将这个变量改为该函数的静态局部变量,以降低模块间的耦合度;

(3)设计和使用访问动态全局变量、静态全局变量、静态局部变量的函数时,需要考虑重入问题,因为他们都放在静态数据存储区,可被其他函数共享;

(4)如果我们需要一个可重入的函数,那么,我们一定要避免函数中使用static变量这样的函数被称为:带“内部存储器”功能的的函数;

(5)函数中必须要使用static变量情况:比如当某函数的返回值为指针类型时,则必须是static的局部变量的地址作为返回值,若为auto类型,则返回为野指针。

参考文献

[1] http://blog.csdn.net/yunyun1886358/article/details/5632087

[2] C++高级进阶教程.陈刚.武汉大学出版社

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-07 17:16:23

C++中的作用域与生命周期的相关文章

C/C++——C++变量的作用域与生命周期,C语言中变量的作用域和生命周期

全局变量 作用域:全局作用域(全局变量只需在一个源文件中定义,就可以作用于所有的源文件.) 生命周期:程序运行期一直存在 引用方法:其他文件中要使用必须用extern 关键字声明要引用的全局变量. 内存分布:全局数据区 注意:如果在两个文件中都定义了相同名字的全局变量,连接出错:变量重定义 全局静态变量 作用域:文件作用域(只在被定义的文件中可见.) 生命周期:程序运行期一直存在 内存分布:全局数据区 定义方法:static关键字,const 关键字 注意:只要文件不互相包含,在两个不同的文件中

MyBatis 作用域和生命周期

理解到目前为止所讨论的类的作用域和生命周期是非常重要的.如果使用不当可导致严重的并发性问题. SqlSessionFactoryBuilder  这个类可以在任何时候被实例化.使用和销毁.一旦您创造了SqlSessionFactory 就不需要 再保留它了.所以SqlSessionFactoryBuilder 实例的最好的作用域是方法体内(即一个本地方法 变量).您能重用SqlSessionFactoryBuilder 创建多个SqlSessionFactory 实例,但最好不要把 时间.资源放

文件载入流程,函数的使用【函数名,参数【按引用赋值的问题】,函数体,【变量作用域和生命周期】】

1.求最大公约数辗转相除求值例如:12,8求最大公约数12%8=4[不为零]8%4=0[为零,则4为最大公约数][原理就是12,8的最大公约数和8,4的最大公约数一致][这个问题已经可被证明]计算机中最早的算法 2.文件载入---流程[php执行的先后顺序][php对代码的编译以文件为单位]先检查一个文件中的语法再进行编译然后才会一行行解释执行 [这一点需要注意]这里进行文件载入的流程讲解:php文件载入时,被引入的文件中的语法并不会解析,只有当该文件被执行[也就是被引入语句之后的部分才会报错]

嵌入式 Linux C语言(八)——存储类型、作用域、生命周期、链接属性

嵌入式 Linux C语言(八)--存储类型.作用域.生命周期.链接属性 一.存储类型 C语言中,每个变量和函数都有两个属性:数据类型和数据的存储类型. 变量的存储类型是指存储变量值的内存类型.变量的存储类型决定变量何时创建.何时销毁以及它的值将保持多久.计算机中有三个地方可以用于存储变量:普通内存,运行时堆和栈,硬件寄存器.变量的存储类型取决于声明变量的位置. C语言存储类别说明符: 说明符 用    法 auto 只在代码块内变量声明中被允许, 表示变量具有本地生存期 extern 出现在顶

存储类、作用域、生命周期、链接属性

1.linux下C语言程序的内存映像代码段(.text).数据段(.data).bss段.栈.堆的概念 代码段(.text) (1)对应着程序中的代码(函数),代码段在linux中又叫文本段(.text)(2)部分平台下的const修饰的变量. 数据段(.data) 1.显式初始化为非0的全局变量: 2.显式初始化为非0的static局部变量 bss段 1.显式初始化为0或者未显式初始化的全局变量: 2.显式初始化为0或未显式初始化的static局部变量. 栈 局部变量分配在栈上:函数调用传参过

7、C_存储类 &amp;amp; 作用域 &amp;amp; 生命周期 &amp;amp; 链接属性

概念解析 存储类 存储类就是存储类型,也就是描述C语言变量在何种地方存储. 内存有多种管理方法:栈.堆.数据段.bss段..text段······一个变量的存储类属性就是描述这个变量存储在何种内存段中. 譬如:局部变量分配在栈上,所以它的存储类就是栈:显式初始化为非0的全局变量分配在数据段,显式初始化为0和没有显示初始化(默认为0)的全局变量分配在bss段. 作用域 作用域是描述这个变量起作用的代码范围. 基本来说,C语言变量的作用域规则是代码块作用域.意思就是这个变量起作用的范围是当前的代码块

Spring之Bean的作用域与生命周期

在前面博客中提到容器启动获得BeanDefinition对象中有一个scope 属性.该属性控制着bean对象的作用域.本章节介绍Bean的作用域及生命周期,了解bean是怎么来的又怎么没的. 一.Bean的作用域在Bean容器启动会读取bean的xml配置文件,然后将xml中每个bean元素分别转换成BeanDefinition对象.在BeanDefinition对象中有scope 属性,就是它控制着bean的作用域.Spring框架支持5种作用域,有三种作用域是当开发者使用基于web的App

spring作用、spring注解、管理对象的作用域与生命周期、自动装配

Spring 1. 作用 创建和管理对象,使得开发过程中,可以不必使用new关键字创建对象,而是直接获取对象!并且,还可以通过一些配置,使得某些获取到的对象,其中某些属性已经是被赋值的! 2. Spring注解 在Spring中,定义了一系列的注解,可以取代几乎所有的XML配置! 尽管使用注解可以完成此前的许多配置,但是,基于Spring的项目仍需要Spring的配置文件! 2.1. 常用注解 使用注解的方式来创建和管理对象,首先,必须在Spring的配置文件中添加组件扫描: <!-- 组件扫描

Bean 注解(Annotation)配置(2)- Bean作用域与生命周期回调方法配置

Spring 系列教程 Spring 框架介绍 Spring 框架模块 Spring开发环境搭建(Eclipse) 创建一个简单的Spring应用 Spring 控制反转容器(Inversion of Control – IOC) 理解依赖注入(DI – Dependency Injection) Bean XML 配置(1)- 通过XML配置加载Bean Bean XML 配置(2)- Bean作用域与生命周期回调方法配置 Bean XML 配置(3)- 依赖注入配置 Bean XML 配置(