static关键字详解(C/C++)

简介: static关键字详解(C/C++)

前言

static关键字在C/C++/JAVA编程语言中都存在,而且在编程中经常会遇到,那么,在C/C++中,static究竟意味着什么?那么static修饰的变量和函数有什么样的特点呢?

本篇内容提要:

可以说,所有的静态变量都有几个共同特点:

  1. 在main函数执行之前就分配了内存(分配在全局数据区),整个程序执行完才会被销毁;
  2. 若没有初始化,会被程序自动初始化为0

1.静态局部变量

一般的局部变量有一个问题,就是生命周期短,所以我们经常会定义全局变量,但是在实际的开发中,若全局变量定义太多,很容易出现重名的问题,而且也不容易区分,所以在一般的开发中,并不会定义过多的全局变量。

静态局部变量同时具备局部变量的防重复和生命周期长两个优点,可以很好地解决这个问题。

比方说:

#include <iostream>
void print_fun()
{
  static int a = 0;
  a++;
  printf("a = %d\t", a);
}
int main()
{
  int add = 0;
  while (add < 10)
  {
    print_fun();
    add++;
  }
  printf("\n");
}

打印输出:

从以上这个简单的例子,就可以说明问题。

2.静态全局变量

与局部静态变量类似,只不过静态全局变量虽然也是全部变量,但是仅限在本文件中使用。例如;

mian.cpp文件中程序如下:

#include <iostream>
extern short ex;
int main()
{
  printf("%d\n", ex);
}

而在example.c文件中,程序如下:

#include <iostream>
static short ex = 0;

运行,出现如下问题:

可以看出,被static修饰的全局变量,仅仅作用在本文件中,其他文件中无法使用。

3.静态函数

静态函数相对来说比较简单,同样是对外不可见的。例如;

mian.cpp文件中编写程序如下:

#include <iostream>
#include "example.h"
int main()
{
  static_print_ex();
}

example.h中编写程序如下:

#pragma once
extern short ex;
static void static_print_ex();

example.cpp中编写程序如下:

#include <iostream>
#include "example.h"
static void static_print_ex()
{
  printf("The static external function is called!");
}

执行后,出现如下错误:

而在该函数的声明和定义中去掉static后,再次执行,打印输出如下:

可以看到,程序可以正常执行,也就是静态函数的应用场景就是:

部分函数只想在本文件中使用,为了避免在其他文件中被使用,就可以采用这样的方法。

这个很好解释,就好比const关键字一样,即使我们知道变量定义的时候知道是常量,不想再二次赋值,但是在后续的开发中,为了防止该变量的值被修改,还是会加上const关键字。

4.静态成员变量

因为静态数据成员在全局数据区分配内存,由本类的所有对象共享,所以,它不属于特定的类对象,不占用对象的内存,而是在所有对象之外分配内存,在没有产生类对象时其作用域就可见。因此,在没有类的实例存在时,静态成员变量就已经存在,我们就可以操作它。例如:

假设有个用户类Userm_Usersum是当前系统中某产品的用户数量,所以在任何实例中,查询用户数量都是一样的,然而当某地的用户数量增加的时候,整个产品总的用户数量也会随之增加。

#include <iostream>
class User
{
public:
  static int m_Usersum;
  static void SetUsersum(const int sum)
  {
    m_Usersum = sum;
  }
  static int GetUsersum()
  {
    return m_Usersum;
  }
};
int User::m_Usersum = 100;
int main()
{
  User *User1;
  printf("There are %d users!\n", User1->GetUsersum());
  User1->SetUsersum(101);
  User *User2;
  printf("There are %d users!\n", User2->GetUsersum());
  User2->SetUsersum(102);
  printf("There are %d users!\n", User1->GetUsersum());
  printf("There are %d users!\n", User2->GetUsersum());
}

打印输出:

可以看到,静态成员变量对每个类都是一样的,共享的,因为无论有多少个类,静态成员变量在内存中只有一份,所以无论在哪个实例中修改变量的值,在其他类中获取到的值都是一样的。

然后验证一下在类实例化之前访问静态成员变量。

编写代码如下:

#include <iostream>
class User
{
public:
  static int m_Usersum;
  static void SetUsersum(const int sum)
  {
    m_Usersum = sum;
  }
  static int GetUsersum()
  {
    return m_Usersum;
  }
};
int User::m_Usersum = 100;
int main()
{
  printf("There are %d users!\n", User::m_Usersum);
}

打印输出:

可以看到,在类没有实例化的时候,静态成员变量已经初始化成功,我们可以随时访问。

5.静态成员函数

1.与普通函数相比,静态成员函数属于类本身,而不作用于对象,因此它不具有this指针。

这句话如何理解呢?

静态成员函数确实属于类,但是和类的对象关系不大,不会牵扯到类的构造析构当中来,所以也不会有this指针。

关于this指针,网上有这样一段描述:

首先,我们都知道类的成员函数可以访问类的数据(限定符只是限定于类外的一些操作,类内的一切对于成员函数来说都是透明的),那么成员函数如何知道哪个对象的数据成员要被操作呢,原因在于每个对象都拥有一个指针:this指针,通过this指针来访问自己的地址。

2.静态成员函数不能访问非静态成员函数和非静态成员变量

这时候为什么呢?

还是和创建时间有关系,静态成员函数在类的实例化之前就已经存在了,这个时候类还没来得及实例化,根本无法访问非静态成员函数和非静态成员变量。

可以验证一下在类实例化之前访问静态成员函数。

#include <iostream>
class User
{
public:
  static int m_Usersum;
  static void SetUsersum(const int sum)
  {
    m_Usersum = sum;
  }
  static int GetUsersum()
  {
    return m_Usersum;
  }
};
int User::m_Usersum = 100;
int main()
{
  printf("There are %d users!\n", User::GetUsersum());
}

打印输出:

可以看到,程序可以正常运行。

参考文献

知乎:C/C++ 中的static关键字

哔哩哔哩:C语言关键字static使用及其注意事项

----------------------------------------------------------------------------------END----------------------------------------------------------------------------------

相关文章
|
2月前
|
存储 编译器 C语言
详解C/C++中的static和extern
本文详解了C/C++中`static`和`extern`关键字的用法和区别,通过具体代码示例说明了在不同情境下如何正确使用这两个关键字,以及`extern "C"`在C++中用于兼容C语言库的特殊作用。
详解C/C++中的static和extern
|
1月前
|
存储 编译器 C++
【C++】深入探索类和对象:初始化列表及其static成员与友元(一)
【C++】深入探索类和对象:初始化列表及其static成员与友元
|
1月前
|
C语言 C++
C 语言的关键字 static 和 C++ 的关键字 static 有什么区别
在C语言中,`static`关键字主要用于变量声明,使得该变量的作用域被限制在其被声明的函数内部,且在整个程序运行期间保留其值。而在C++中,除了继承了C的特性外,`static`还可以用于类成员,使该成员被所有类实例共享,同时在类外进行初始化。这使得C++中的`static`具有更广泛的应用场景,不仅限于控制变量的作用域和生存期。
46 10
|
1月前
|
存储 编译器 数据安全/隐私保护
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解2
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解
29 3
|
1月前
|
编译器 C++
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解1
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解
43 3
|
1月前
|
C++
【C++】深入探索类和对象:初始化列表及其static成员与友元(二)
【C++】深入探索类和对象:初始化列表及其static成员与友元
|
1月前
|
编译器 C++
【C++】深入探索类和对象:初始化列表及其static成员与友元(三)
【C++】深入探索类和对象:初始化列表及其static成员与友元
|
2月前
|
C++
C/C++静态链接pthread库的坑【-static -pthread】
C/C++静态链接pthread库的坑【-static -pthread】
|
4月前
|
存储 安全 编译器
【C++入门 四】学习C++内联函数 | auto关键字 | 基于范围的for循环(C++11) | 指针空值nullptr(C++11)
【C++入门 四】学习C++内联函数 | auto关键字 | 基于范围的for循环(C++11) | 指针空值nullptr(C++11)
|
4月前
|
存储 编译器 C++
C++从遗忘到入门问题之float、double 和 long double 之间的主要区别是什么
C++从遗忘到入门问题之float、double 和 long double 之间的主要区别是什么