static和const

发布时间 2023-07-23 17:48:02作者: 小凉拖

static

static修饰的变量存储于全局区,而初始化的和未初始化的在全局区分开储存,如果没显示初始化会被程序自动初始化为0

对于局部变量

  • static延长了它的生命周期,即不随函数的销毁而销毁,只有程序运行结束才会销毁
  • static使得局部变量只在第一次调用的时候初始化,之后的调用不再初始化,不运行初始化代码
  • static修饰的局部变量具有记忆性可以将上次的调用结果保存下来作为下次调用的初值
  • static相比于全局变量的好处在于,由于它没有改变作用域,因此只能在函数内使用,受函数控制维护起来方便

对于全局变量

  • static改变的是它的作用域,即只能在本文件中使用,不能被外部文件进行extern声明并使用,想要在外部使用必须在外部文件中包含static全局变量定义的文件的文件名,这相当于将该文件的所有内容在外部文件中重新写了一遍
  • static修饰的全局变量作用在于防止各文件定义同名的全局变量,而导致名称冲突

对于函数

它和全局变量一样

补充知识

 

1.栈区:由编译器自动分配释放,像局部变量,函数形参,都是在栈区。会随着作用于退出而释放空间。

 

2.堆区:程序员分配并释放的区域,像malloc(c),new(c++)

 

3.全局数据区(静态区):全局变量与静态变量的存储是放在一起的,初始化的全局变量与静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域,程序结束释放。

 

4.代码区

 

C++的static

以上是C的static,C++的static在C的基础上增添了关于类的用法

static修饰的成员变量

其实与其说增添了关于类的用法还不如说对类使用static修饰的局部变量的属性

  • 首先,static修饰的成员属性(叫做静态成员变量)存储在全局区,这就意味着它不占用类的内存空间,这就意味着静态成员函数不能在类声明中定义;静态全局变量只有一份,所有实例化的对象共享这个静态全局变量,因此静态成员变量也称为类变量,这使得我们不仅可以用普通成员变量的访问方式访问还可以使用Rectangle::s_sum的形式访问。
  • 静态成员变量不随实例化的对象销毁而销毁,只有程序运行结束才会销毁。
  • 静态成员变量只在实例化第一个对象的时候初始化,之后不再初始化,不运行初始化代码
  • 静态成员变量具有记忆性,可以将上次实例化对象时赋予静态变量的结果保存下来,作为下次实例化对象的初值

由此可见C++对于static的使用和C语言对于static在局部变量的使用是一模一样,只不过函数替换成了实例化对象,又增添了一些类的东西

 1 #include <iostream>
 2 using namespace std;
 3 
 4 class Rectangle
 5 {
 6 private:
 7     int m_w, m_h;
 8     static int s_sum;
 9 
10 public:
11     Rectangle(int w, int h)
12     {
13         this->m_w = w;
14         this->m_h = h;
15         s_sum += (this->m_w * this->m_h);
16     }
17 
18 
19     void GetSum()
20     {
21         cout << "sum = " << s_sum << endl;
22     }
23 
24 
25 };
26 
27 int Rectangle::s_sum = 0;  //初始化
28 void test01()
29 {
30     Rectangle rect1(3, 4);
31     rect1.GetSum();
32     cout << "sizeof(rect1)=" << sizeof(rect1) << endl;
33 }
34 
35 int main()
36 {
37     cout << "sizeof(Rectangle)=" << sizeof(Rectangle) << endl;
38     test01();
39     Rectangle rect2(2, 3);
40     rect2.GetSum();
41     cout << "sizeof(rect2)=" << sizeof(rect2) << endl;
42 
43     system("pause");
44     return 0;
45 }

 

所有的大小等于8意味着:

静态成员变量不占用类的内存空间,且只有一份

18=12+6意味着

  • 静态成员变量不随实例化的对象销毁而销毁(test01函数结束后rect1被销毁),只有程序运行结束才会销毁
  • 静态成员变量只在实例化rect1的时候初始化,之后不再初始化,不运行初始化代码
  • 静态成员变量具有记忆性,可以将上次实例化rect1时赋予静态变量的结果保存下来,作为下次实例化rec2的初值

static修饰的成员函数

static修饰的成员函数称为静态成员函数

静态成员函数和静态成员变量类似,所有对象所共享,可以类内定义也可以类外定义,可以使用::来调用,最重要的是非静态成员函数没有this指针,因此静态成员函数不能访问非静态成员函数和非静态数据成员,因为没有this指针静态成员函数不知道这个非静态成员变量到底是属于哪个对象的

总的来说:

 

1.静态成员之间可以相互访问,包括静态成员函数访问静态数据成员和访问静态成员函数。

 

2.非静态成员函数可以任意的访问静态成员函数和静态数据成员。

 

3.静态成员函数不能访问非静态成员函数和非静态数据成员。

参考文章:

(103条消息) c++中的static详解_c++ static_大楠树的博客-CSDN博客

值得注意的是静态成员函数,静态成员变量,非静态成员函数均只有一份,不占用类的内存,那么非静态成员函数怎么知道谁在调用它呢,答案是使用this指针,也就是说谁调用这个函数this指针就指向谁

const

与static讨论的是作用域生命周期以及存储的问题不同的是const主要讨论的是访问权限的问题,即只读

const不考虑类的情况

const常量必须显示初始化,初始化后不可更改

非const类型可以转换成const类型

const考虑类的情况

const成员变量

  • const成员变量必须通过初始化列表进行初始化(const成员变量,引用,没有提供默认构造函数的类类型必须通过初始化列表进行初始化)
  • 每个实例化对象都有它们自己const成员变量

常函数

首先理解下this指针,this指针本质是一个指针常量,它只能指向当前调用这个成员函数的实例化对象,此时它的指向不可以更改,(this指针不算类的数据成员,它相当于是成员函数默认隐含的第一个参数,每当一个对象调用成员函数则将对象的地址(可能不是地址就只是偏移量)传递给this)下面的程序类似的解释了this的原理。

 

 1 class Person {
 2 public:
 3 
 4     int m_ = 10;
 5 };
 6 void fun(Person* const _this) {
 7 
 8 }
 9 int main()
10 {
11     Person p1;
12     Person p2;
13     fun(&p1);
14     fun(&p2);
15     system("pause");
16     return 0;
17 }

 

 

 

 

如果是常函数则它的this指针是const *const类型的那么除了它的指向不可以修改,它指向成员变量的值也不可以修改,也就是说不可以在常函数内部修改普通的成员变量

 但是常函数内部可以修改mutable修饰的成员变量

 常对象修改mutable修饰的成员变量,可以修改静态成员变量,只能调用常函数

普通对象不能修改const修饰的成员变量,其他都可以修改和调用

 1 #include <iostream>
 2 using namespace std;
 3 
 4 class Person {
 5 public:
 6     Person(int h) :h_(h) {
 7 
 8     }
 9     int m_ = 10;
10     const int h_;
11     mutable int n_ = 20;
12     static int y_;
13     void fun() {
14 
15     }
16     void func()const {
17 
18     }
19 };
20 int Person::y_ = 40;
21 int main()
22 {
23     const Person p1(3);
24     p1.m_ = 20;//错误
25     p1.h_ = 30;//错误
26     p1.n_ = 40;
27     p1.y_ = 50;
28     p1.fun();//错误
29     p1.func();
30     Person p2(4);
31     p2.m_ = 20;
32     p2.h_ = 30;//错误
33     p2.n_ = 40;
34     p2.y_ = 50;
35     p2.fun();
36     p2.func();
37     system("pause");
38     return 0;
39 }