• C++静态成员(static)


    一、什么是静态成员

    由关键字static修饰类体中成员,称为类静态成员(static class member)。类的静态成员为其所有对象共享,不管有多少对象,静态成员只有一份存于公共内存中。静态数据成员被当作该类类型的全局对象。

    二、静态属性

    在类设计中,用关键字static修饰的数据成员为静态数据成员。由该类型实例化的所有对象,共享系统为静态成员分配的一个存储空间,而这个存储空间是程序执行main函数之前分配的,在实例化对象时不再为静态成员分配空间(静态成员数据不在对象空间中)。

    1、设计静态数据成员目的是信息共享;

    示例:

    1. class Circle
    2. {
    3. private:
    4. double pi; //
    5. double radius; // 半径
    6. public:
    7. Circle(double r = 0.0):pi(3.14),radius(r) {}
    8. ~Circle() {}
    9. void area() const
    10. {
    11. return pi * radius * radius;
    12. }
    13. };
    14. int main()
    15. {
    16. Circle cir(12.23);
    17. cir.area();
    18. size_t sz = sizeof(cir);
    19. return 0;
    20. }

     全局变量:

    1. double pi = 3.14;
    2. class Circle
    3. {
    4. private:
    5. double radius; // 半径
    6. public:
    7. Circle(double r = 0.0):pi(3.14),radius(r) {}
    8. ~Circle() {}
    9. void area() const
    10. {
    11. return pi * radius * radius;
    12. }
    13. };

    类的静态数据成员:

    1. class Circle
    2. {
    3. private:
    4. //静态成员的声明,注意私有
    5. static double pi;
    6. private:
    7. double radius;
    8. public:
    9. Circle(double r = 0.0):pi(3.14),radius(r) {} //error
    10. Circle(double r = 0.0):radius(r) {} // ok;
    11. Circle(double r = 0.0):radius(r)
    12. {
    13. pi = 3.14; // ok; 但是没有必要
    14. }
    15. };
    16. //静态成员的定义
    17. double Circle::pi = 3.14;

    总结:

    同全局变量相比,使用静态数据成员有两个优势:

    1、静态数据成员没有进入程序的全局名字空间,因此不存在与程序中其他全局名字冲突的可能性。

    2、可以实现信息隐藏,静态成员可以是private成员,而全局变量不能。 

    2、静态数据是该类所有对象所共有的,可提供同一类型的所有对象之间,信息共享或信息交换的一种方式。

    静态数据成员属于整个类型,使用时可用以下格式:

    类名::静态数据成员名 或 对象.静态数据成员名(前提是可访问符为public)

    示例:

    用静态数据成员记录由同一类建立的对象的数量。

    定义学生类,统计学生的信息:

    • 通过定义一个全局变量统计当前学生总数,全局变量可以实现对象的共享,但是没有权限的限制,导致其他的函数或者对象可以无限制修改,则会出现问题(不安全);
    • 使用static,利用普通成员变量进行统计,普通成员变量是本类某个对象独有的,类作用域,不能实现共享,外界修改不了(比较安全)。
    1. int m_count = 0;//1、全局变量
    2. //全局变量可以实现对象的共享,但是没有权限的限制,导致其他的函数或者对象可以无限制修改,则会出现问题(不安全)
    3. class Student
    4. {
    5. public:
    6. Student(int num = 0, const char* name = "", char sex = 'm'):m_num(num), m_sex(sex)
    7. {
    8. m_name = new char[strlen(name) + 1];
    9. strcpy_s(m_name, strlen(name) + 1, name);
    10. m_count++;
    11. }
    12. ~Student()
    13. {
    14. if (m_name != NULL)
    15. {
    16. delete[]m_name;
    17. m_name = NULL;
    18. }
    19. }
    20. void Print(){
    21. cout << "总数" << m_count << endl;
    22. }
    23. private:
    24. int m_num;
    25. char* m_name;
    26. char m_sex;
    27. static int m_count;//2、普通成员变量是本类某个对象独有的,类作用域,不能实现共享,外界修改不了(比较安全)
    28. };
    29. int Student::m_count;
    30. void main()
    31. {
    32. Student s(1001, "张三", 'm');
    33. Student s1(1003, "张三", 'w');
    34. Student s2(2005, "张三", 'm');
    35. s.Print();
    36. s1.Print();
    37. s2.Print();
    38. }

    3、在类的成员函数中使用静态数据成员,静态数据成员之前没有this

    1. class Cat // 猫
    2. {
    3. private:
    4. static int num;
    5. private:
    6. std::string _owner; //猫主
    7. std::string _name; //猫名
    8. public:
    9. Cat(const string &owner,
    10. const string &name):_owner(owner),_name(name)
    11. {
    12. num+=1;
    13. cout<<"create Cat num: "<< num<
    14. }
    15. ~Cat()
    16. {
    17. num-=1;
    18. cout<<"Destroy Cat num: "<
    19. }
    20. void print() const
    21. {
    22. cout<<"Owner: "<<_owner<<" Name: "<
    23. num+=1; // not this;
    24. }
    25. };

    4、若类中含有静态成员,则该成员不在能本类中开辟空间,静态数据成员不占类的大小,不能在构造函数中初始化。

    1. class A
    2. {
    3. public:
    4. //A():m_a(1),m_b(2),m_c(3){}//m_c不能在构造函数中初始化
    5. A() :m_a(1), m_b(2)
    6. {
    7. //m_c = 3;//赋值, 没有给m_c开辟空间
    8. m_c++;
    9. }
    10. void Print()
    11. {
    12. cout << m_c << endl;
    13. }
    14. private:
    15. int m_a;//4
    16. char m_b;//1 1->4
    17. static int m_c;//m_c没有在A类开辟空间
    18. //引用性声明,仅用于声明
    19. };
    20. int A::m_c = 0;//定义性声明 开辟空间
    21. void main()
    22. {
    23. cout << sizeof(A) << endl;
    24. A a;
    25. a.Print();
    26. A b;
    27. b.Print();
    28. }

    5、静态属性的类型是int,short,char,并且是const,可以在类中直接初始化

    1. class Bar
    2. {
    3. private:
    4. static const int nameSize = 20; // ok;
    5. static const char name[nameSize]="xiao cheng bar"; // error;
    6. };

     6、静态数据成员的类型可以是其所属类,而非static数据成员只能被声明为该类的指针

    1. class Bar
    2. {
    3. private:
    4. std::string _name;
    5. private:
    6. static Bar sm_bar; // ok;
    7. private:
    8. Bar m_bar; // error;
    9. Bar *pb; // ok;
    10. };

    总结:

    1、设计静态数据成员目的是信息共享和信息交流

    2、类的静态数据成员为所有类对象所共享,不属于某个具体的实例

    3、类的静态数据成员必须在类外定义,定义时不添加static关键字,不能在构造函数的初始化列表中创建

    4、类的静态数据成员类型是int,short,char,long long,并且是const,可以在类中直接初始化,也可以在类外初始化

    5、在类的成员函数中使用静态数据成员,静态数据成员之前没有this

    6、当类的静态数据成员为公有时,可以在外部函数使用:类名::静态数据成员名 或 对象.静态数据成员名,可以在类体中定义自身的静态类型对象

    三、静态方法 

    函数成员说明为静态,将与该类的不同对象无关。静态函数成员的调用,在对象之外可以采用下面的方式:

    类名::函数名 或 对象名.函数名

    与静态数据成员相反,为使用方便,静态函数成员多为公有。

    1. class Object
    2. {
    3. private:
    4. static int num;
    5. private:
    6. int value;
    7. public:
    8. Object(int val = 0):value(val),num(val) {}// error;静态属性只能在类外初始化
    9. Object(int val):value(val)
    10. {
    11. num = 1; // 不是初始化,是赋值
    12. }
    13. void print()
    14. {
    15. cout<<"value: "<" num: "<
    16. }
    17. static void show() // 静态函数 not this
    18. {
    19. cout<<"value: "<" num: "<
    20. }
    21. static void fun(Object &obj) // const // 不能定义为常方法。
    22. {
    23. cout<" "<
    24. }
    25. };
    26. int Object::num = 0;

     静态成员函数没有this指针,因此在静态成员函数显式地使用this指针都将导致编译时刻错误。试图访问隐式使用this指针所指向的非静态数据成员也会导致编译时刻错误。

    1. class Student
    2. {
    3. public:
    4. Student(int num = 0, const char* name = "", char sex = 'm') :m_num(num), m_sex(sex)
    5. //m_count(0),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. cout << "总数" << m_count << endl;
    21. }
    22. //在static函数中,没有this指针,所以不能直接输出非静态数据成员
    23. static void Show(Student &s )
    24. {
    25. cout << "Show" << endl;
    26. cout << s.m_num << s.m_name << s.m_sex << m_count << endl;
    27. }
    28. private:
    29. int m_num;
    30. char* m_name;
    31. char m_sex;
    32. static int m_count;
    33. //const int m_j;//成员初始化列表
    34. //const static int m_i = 20;
    35. };
    36. int Student::m_count;
    37. void main()
    38. {
    39. Student s(1001, "张三", 'm');
    40. Student s1(1003, "张三", 'w');
    41. Student s2(2005, "张三", 'm');
    42. s.Print();
    43. s1.Print();
    44. s2.Print();
    45. s.Show(s);//没有this指针来接收,不管是用哪个对象来调用static,本质使用当前对象的类型Student来调用
    46. Student::Show(s2);//right,不用特别去声明成员调用此函数
    47. //Student::Print();//error,非静态只能用对象来调用,非static中,有this指针,必须通过对象来调用
    48. }

     总结:

    一个常规的成员函数声明描述了三件在逻辑上相互不同的事情:

    • 该函数能访问类声明的私用部分。
    • 该函数位于类的作用域之中。
    • 该函数必须由一个对象去激活(有一个this指针)。

    将一个函数声明为友元可以使它只具有第一种性质。

    将一个函数声明为static可以使它只具有第一种和第二种性质。

  • 相关阅读:
    C#对字典容器Dictionary<TKey, TValue>内容进行XML序列化或反序列化报错解决方法
    利用 Python PyPDF2库轻松提取PDF文本(及其他高级操作)
    Machine learning week 5(Andrew Ng)
    c++/c图的邻近矩阵表示
    MSDC 4.3 接口规范(21)
    文件加密系统是如何实现企业数据高效安全保护的?
    Verilog task使用说明
    【论文极速读】Prompt Tuning——一种高效的LLM模型下游任务适配方式
    关于POM声明为provided的依赖,运行程序时报错NoClassDefFoundError
    汽车油耗NEDC与WLTP有什么区别?以及MATLAB/Simulink的汽车行驶工况仿真
  • 原文地址:https://blog.csdn.net/weixin_59179454/article/details/127759353