关于C++中static关键字的总结


因为最近要保研和找实习,所以重新复习了一下C++的知识,static的用法很丰富,就想整理一下。

一、用在局部作用域

首先回顾一下作用域的概念:

作用域是指一个标识符在程序正文中有效的区域。对于函数体内的变量,作用域从声明处起到所在块结束的大括号为止,对于函数的形参,从声明处起到函数体结束为止。

在局部作用域中,如果一个对象声明为static,即在对象的声明前加上“static”关键字,则该对象具有静态生存期,这个对象不会随着多次函数调用而产生一个副本,也不会因为函数的返回而失效。
由于函数返回之后,在函数外部实际上无法访问static的对象,所以static的函数用法多出现在递归的函数中。

int factorial(int n){
    static int result=1;
    if(n==0){
        return result;
    }else{
        return n * factorial(n-1);
    }
}

比如上面的函数,result变量为static,在多次调用中只会初始化第一次,这里初始化为1。需要注意的是,动态基本类型变量未初始化会被赋予随机值,静态基本类型变量则默认初值为0。

二、用在全局作用域

在全局作用域中的变量,在整个文件中都有效。但是不加static的变量和函数,则默认是extern变量,在该模块以外的所有模块中都是可见的。这带来的问题是,不同人开发的模块很可能出现变量重名,当多文件工程很大需要引用多个模块时更是如此,所以我们需要隐藏一些不必要外部可见的变量。
static正是提供了这一功能。被static修饰的变量或函数,无法被其他编译单元引用。

在ISO C++ 2.0标准中不再鼓励这种用法,如果想要隐藏该模块的变量和函数不为外部可见,鼓励使用匿名命名空间的方式。由于每个源文件的匿名空间是不同的,所以在一个源文件中没有办法访问其他源文件的匿名命名空间。

以下为一个多文件项目:
a.cpp

#ifndef UNTITLED_A_H
#define UNTITLED_A_H
void func1();
static void func2();
#endif //UNTITLED_A_H

a.cpp

#include <iostream>
#include "a.h"
using namespace std;
void func1(){
    cout << "func1" << endl;
}
static void func2(){
    cout << "func2" << endl;
}

main.cpp

#include <iostream>
#include "a.h"
using namespace std;
int main() {
    func1();
    func2();
    return 0;
}

这里func1()是外部可见的,func2()是外部不可见的,因此会提示如下错误:
warning: 'void func2()' used but never defined

三、用在类作用域

这里分为静态数据成员和静态函数成员。

1. 静态数据成员

如果一个类中的数据成员用static修饰,该成员不属于任何一个对象独有,而是整个类所共有。该变量将具有静态生存期,而且可以不通过对象,而是通过类的方式“类名::标识符”直接访问。

2. 静态函数成员

同理,如果一个函数用static修饰,则该函数为整个类所共有的函数,可以直接通过“类名::函数名(参数)”来调用。当然通过对象名调用也是可以的,等价于通过类名来调用。

下面举个例子来说明两种静态成员。

#include <iostream>
using namespace std;
class A{
public:
    A(){
        cout << "constructor"<<endl;
        count ++;
    }
    A(A &a){
        cout << "copy constructor"<<endl;
        count ++;
    }
    static int getcount(){
        return count;
    }
private:
    static int count;
};
int A::count = 0;
int main() {
    cout << A::getcount()<<endl;
    A a;
    A b = a;
    cout << A::getcount()<<endl;
    return 0;
}

这里count为static变量,这里注意c++的类静态数据成员变量必须在类外初始化,即使该变量为private类型。getcount是一个类的静态函数成员,可以不依赖类的对象调用。
在主函数中,还没有一个对象存在时,getcount函数就可以返回count值,此时为初始化的0。当声明了两个对象之后,getcount的值将会变成2。
运行结果:

0
constructor
copy constructor
2

四、static变量的存放位置

对于c++来讲,编译运行程序占用内存大体分为数据段和代码段,数据段又可分为:全局存储区,堆区,栈区,常量存储区。
函数存放在代码段中,static修饰的变量和全局变量都放在全局存储区中。全局存储区又可分为初始化的数据段(.data)和未初始化的数据段(.bss)。如果static变量可以在程序运行前确定初值,将放入.data中,如果不能,比如static变量是通过执行构造函数赋予初值,则无法在运行前确定初值,则放入未初始化的数据段.bss中。

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

薛钦亮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值