• C++之static,静态变量


    目录

    1.为什么要用静态变量

    2.全局变量

    3.静态局部变量

    4.静态数据成员的空间开辟

    5.静态数据成员

    6.释放

    7.总结

    1.内存:

    2.初始化:

    3.最大的优点:

    4.指针:

    5.释放时机:


    1.为什么要用静态变量

    前面我们定义学生类统计学生信息,只统计了学生的学号、姓名、性别,如果现在我们计算统计的学生的数量,我们该怎么做?

    普通成员变量是本类某个对象:

    1. class Student
    2. {
    3. public:
    4. Student(int num = 0, const char* name = "", char sex = 'm') :m_count(0),m_num(num), m_sex(sex)
    5. {
    6. m_name = new char[strlen(name) + 1];
    7. strcpy_s(m_name, strlen(name) + 1, name);
    8. m_count++;
    9. }
    10. ~Student()
    11. {
    12. if (m_name != NULL)
    13. {
    14. delete[]m_name;
    15. m_name = NULL;
    16. }
    17. }
    18. void Print()
    19. {
    20. cout << "总数" << m_count << endl;
    21. }
    22. private:
    23. int m_num;
    24. char* m_name;
    25. char m_sex;
    26. int m_count;
    27. };
    28. void main()
    29. {
    30. Student s(1001, "张三", 'm');
    31. s.Print();
    32. Student s1(1002, "李四", 'f');
    33. s1.Print();
    34. Student s2(1003, "王五", 'm');
    35. s2.Print();
    36. }

    我们会发现,三次计算出来的结果都是1,并不是我们所想的1、2、3,这里面的count,每次构造一个心得对象,count都是从0开始计数+1,那我们该怎么让count第一次+1之后第二次构造对象之后计数时从1开始+1得到2呢?

    2.全局变量

    1. int m_count=0;
    2. class Student
    3. {
    4. public:
    5. Student(int num = 0, const char* name = "", char sex = 'm') :m_num(num), m_sex(sex)
    6. {
    7. m_name = new char [strlen(name) + 1];
    8. strcpy_s(m_name, strlen(name) + 1, name);
    9. m_count++;
    10. }
    11. ~Student()
    12. {
    13. if (m_name != NULL)
    14. {
    15. delete[]m_name;
    16. m_name = NULL;
    17. }
    18. }
    19. void Print()
    20. {
    21. cout << "总数" << m_count << endl;
    22. }
    23. private:
    24. int m_num;
    25. char* m_name;
    26. char m_sex;
    27. };
    28. void main()
    29. {
    30. Student s(1001, "张三", 'm');
    31. s.Print();
    32. Student s1(1002, "李四", 'f');
    33. s1.Print();
    34. Student s2(1003, "王五", 'm');
    35. s2.Print();
    36. }

    通过这个我们发现全局变量达到了我们期望的结果,每新构造一个对象,总数加一,但如果一不下心误改了总数,会对结果产生影响吗? 

    1. int m_count=0;
    2. class Student
    3. {
    4. public:
    5. Student(int num = 0, const char* name = "", char sex = 'm') :m_num(num), m_sex(sex)
    6. {
    7. m_name = new char [strlen(name) + 1];
    8. strcpy_s(m_name, strlen(name) + 1, name);
    9. m_count++;
    10. }
    11. ~Student()
    12. {
    13. if (m_name != NULL)
    14. {
    15. delete[]m_name;
    16. m_name = NULL;
    17. }
    18. }
    19. void Print()
    20. {
    21. cout << "总数" << m_count << endl;
    22. }
    23. private:
    24. int m_num;
    25. char* m_name;
    26. char m_sex;
    27. };
    28. void Test()
    29. {
    30. m_count = 10;
    31. }
    32. void fn()
    33. {
    34. m_count = 20;
    35. }
    36. void main()
    37. {
    38. Student s(1001, "张三", 'm');
    39. Student s1(1002, "李四", 'f');
    40. Student s2(1003, "王五", 'm');
    41. s.Print();
    42. Test();
    43. s1.Print();
    44. fn();
    45. s2.Print();
    46. }

     我们发现,s.Print();计算出了最后的总数为三,但经过Test函数后,count被改为10,经过fn函数后又被改为20,那么如果再写一些类似函数,这个count的值会一直被无限修改下去,会出现问题,不能达到我们的目的 error

    总结:

    全局变量可以实现对象的共享

    但是没有权限限制,导致请他的函数或者对象可以无限修改,

    则会出现问题(不安全)

    3.静态局部变量

    1. void fn()
    2. {
    3. int a = 0;
    4. static int b = 0;
    5. a++;
    6. b++;
    7. cout << "a=" << a <<" " << "b=" << b << endl;
    8. }
    9. void main()
    10. {
    11. for (int i = 0; i < 5; i++)
    12. fn();
    13. }

    int a = 0;//第二次来的时候,第一次的空间消失了
    static int b = 0;//第一次遇到b进行初始化,第二次来的时候之前的空间没有消失(在静态存储

    我们发现静态函数再次进入函数没有重新初始化,直接+1,可以用这个解决这个问题。

    4.静态数据成员的空间开辟

    * 静态数据成员的空间开辟?
    *    1.类的声明 .h//多次引用,反复开辟空间
    *    2.类的成员函数的定义文件 user.cpp √
    *    3.测试文件 test.cpp //用户需分辨,还需开辟空间

    1. class A
    2. {
    3. public:
    4. //A():m_a(1),m_b(2),m_c(3){}
    5. A() :m_a(1), m_b(2)
    6. {
    7. m_c = 3;//赋值
    8. }
    9. void Print()
    10. {
    11. cout << m_c << endl;
    12. }
    13. private:
    14. int m_a;
    15. char m_b;
    16. //static int m_c=20;
    17. static int m_c;
    18. };
    19. int A::m_c=10;
    20. //int A::m_a = 2;
    21. void main()
    22. {
    23. cout << sizeof(A) << endl;
    24. A a;
    25. A b;
    26. a.Print();
    27. b.Print();
    28. //cout<
    29. }

    //A():m_a(1),m_b(2),m_c(3){}//m_c不能再构造函数中初始化
    m_c = 3;//赋值
    //static int m_c=20;//还没有空间
    static int m_c;//引用性声明 //不在类中开辟空间,不能在类中进行初始化
    int A::m_c=10;//定义性声明 开辟空间
    //int A::m_a = 2;//error//只有静态可以
    b.Print();// 3 不会因为定义性声明 int A::m_c=10; 而改变
     

     通过A的大小为8我们可以得出,static int m_c;并没有在栈中开辟空间

    5.静态数据成员

    静态数据成员 实现了本类对象的共享,又实现了限制(类作用域)

    1. class Student
    2. {
    3. public:
    4. Student(int num = 0, const char* name = "", char sex = 'm') : m_num(num), m_sex(sex)
    5. {
    6. m_name = new char[strlen(name) + 1];
    7. strcpy_s(m_name, strlen(name) + 1, name);
    8. m_count++;
    9. }
    10. ~Student()
    11. {
    12. if (m_name != NULL)
    13. {
    14. delete[]m_name;
    15. m_name = NULL;
    16. }
    17. }
    18. void Print()
    19. {
    20. cout << m_num<<" "<" "<"总数:" << m_count << endl;
    21. }
    22. //static void Show()
    23. //{
    24. // cout << "Show" << endl;
    25. // //cout << m_num << " " << m_name << " " << m_sex << "总数:" << m_count << endl;
    26. //}
    27. static void Show(Student &s)
    28. {
    29. cout << "Show" << endl;
    30. cout << s.m_num << " " << s.m_name << " " << s.m_sex << "总数:" << m_count << endl;
    31. }
    32. private:
    33. int m_num;
    34. char* m_name;
    35. char m_sex;
    36. static int m_count;
    37. //const int m_i;
    38. //const static int m_count=20;};
    39. int Student::m_count;
    40. void main()
    41. {
    42. Student s(1001, "张三", 'm');
    43. Student s1(1002, "李四", 'f');
    44. s.Print();
    45. Student s2(1003, "王五", 'm');
    46. s1.Print();
    47. s2.Print();
    48. s.Show(s);
    49. Student::Show(s2);
    50. //Student::Print();
    51. };

    //static函数中,没有this指针,所有不能直接输出非static数据成员
        //static void Show()
        //{
        //    cout << "Show" << endl;
        //    //cout << m_num << " " << m_name << " " << m_sex << "总数:" << m_count << endl;
        //}
    static int m_count;//不能在成员初始化列表
    //const int m_i;//成员初始化列表
    //const static int m_count=20;//最好不要这样写,奇怪
    s.Show(s);//不管用哪个对象调用static,其实用的是当前对象的类型
    Student::Show(s2);//静态可以用类直接调用,不依附对象(不声明对象,也可以调用成员函数)//优点:不用特别声明对象调用函数
        //Student::Print();//非static,有this指针,必须通过对象调用

    6.释放

    观察以下代码,试想运行结果

    1. #if 0
    2. class A
    3. {
    4. public:
    5. A() { cout << "A" << endl; }
    6. ~A() { cout << "~A" << endl; }
    7. };
    8. void Test()
    9. {
    10. static A a;
    11. //A b;
    12. }
    13. void main()
    14. {
    15. cout << "main begin" << endl;
    16. for (int i = 0; i < 5; i++)
    17. Test();
    18. cout << "main end" << endl;
    19. }

    cout << "main end" << endl;//在这后面即就是程序结束才调用析构

     第一次调用开辟空间,再遇见不开辟空间也不初始化,等程序执行完毕才释放空间

    7.总结

    1.内存:

    静态局部变量在全局数据区分配内存,局部变量在栈区分配内存

    2.初始化:

    静态局部变量一般在声明处初始化,如果没有显式初始化,会被程序自动初始化为0(局部变量不会执行默认初始化,所以一定要手动初始化,否则会是很奇怪的随机值)

    3.最大的优点:

    可以和全局变量一样只初始化一次,可以将值保存至下一次函数调用时,而访问范围限定在函数内,不被其他地方访问到(局部变量在栈区,在函数结束后立即释放内存,所以局部变量在每次函数调用时都会被初始化)

    4.指针:

    普通成员函数有 this 指针,可以访问类中的任意成员;

    静态成员函数没有 this 指针,不知道指向哪个对象,所以无法访问对象的成员变量,只能访问静态成员(包括静态成员变量和静态成员函数)

    5.释放时机:

     第一次调用开辟空间,再遇见不开辟空间也不初始化,等程序执行完毕才释放空间

  • 相关阅读:
    java运算符
    猿创征文 | 详解二叉树之遍历及其应用(动图遍历演示)
    webpack【实用教程】
    PHP namespace(命名空间) 和 use; 很多人搞不清楚命名空间和使用方法,书上介绍也不清楚看着头大
    Python中以更简洁的方式处理异常,使用装饰器
    概率期望
    msys2 |arch pacman:tesseract ocr 安装 - 思源笔记自动调用
    入门力扣自学笔记278 C++ (题目编号:2605)
    solidty-基础篇-基础语法和定义函数
    [附源码]JAVA毕业设计旅游景点展示平台的设计与实现(系统+LW)
  • 原文地址:https://blog.csdn.net/m0_59052131/article/details/127692271