• 静态 友元 常量


    学习类中的一些特殊的成员,掌握他们的使用以及特点

    一、静态成员

    1、知识点

    一般在.cpp文件中,定义全局变量

    int count=0;

    在.h文件中声明这个全局变量——防止重复包含头文件时,多次定义全局变量

    extern int count;

    类的静态数据成员,在类的实现方法进行初始化(必须初始化)

    public下的静态数据成员可以直接通过类名访问

    1. void fun()
    2. {
    3.    static int a=10;//只会创建一次,第二次调用只会执行下面的a++
    4.    a++;
    5.    cout<
    6. }
    7. int main()
    8. {
    9.    fun();//11
    10.    fun();//12
    11. }

    int a;==>声明

    int a=10;==>初始化:在定义的时候赋值

    赋值:在声明完之后,用“="给标识符赋值

    1.静态成员指的是在c++类中声明成员时,可以加上static关键字,这样声明的成员叫静态成员,静态成员分为静态数据成员和静态函数成员两种

    2、静态数据成员定义

    1. class node
    2. {
    3. public:
    4.    static int id;//静态数据成员定义
    5. }
    6. int node::id=10;//静态数据成员必须在类外初始化

    3、静态数据成员的特点

    1.类中静态数据成员,所有相同类的对象都共享该数据,只有一份内存在内存中

    2.类中的静态数据成员,必须要在类外初始化,因为他不属于对象,属于类,对象存在或者不存在,这个静态数据成员都是存在的

    3.静态数据成员的生命周期是:程序开始就存在(主函数运行之前),直到程序结束才被释放(无论是什么属性)

    4.类中的静态数据成员,可以在类中被重新赋值(必须要在类外初始化之后才能再在类中赋值),可以被普通函数访问

    5.如果该成员是公有属性,那么就还可以在类外被对象自己访问,或者通过类名访问

    访问方式:类名::静态数据

    1. class A
    2. {
    3.    public:
    4.    A()
    5.   {
    6.        cout<<"A构造"<
    7.   }
    8. }
    9. class person
    10. {
    11.    static A* ss//类--包含
    12. static int num;
    13. public:
    14. static int sum;//静态数据成员
    15. void setnum(int num)//给私有属性提供的公有属性接口
    16. {
    17. this->num = num;
    18. }
    19. int getnum()
    20. {
    21. return num;
    22. }
    23. person()
    24. {
    25. sum = 10;//这是赋值操作
    26. num = 20;
    27. }
    28. };
    29. int person::sum = 0;//类外初始化操作
    30. int person::num = 0;
    31. A* person::ss=new A;
    32. //静态数据成员不能在类中初始化,必须要在类外初始化
    33. //类型 类名::静态成员=值
    34. int main()
    35. {
    36. person p;//实例化对象
    37. cout << p.sum << endl;
    38. cout << p.getnum() << endl;
    39.    
    40. person p1;
    41. p1.setnum(99);
    42. cout << p.getnum() << endl;
    43. cout << p1.getnum() << endl;
    44.    
    45.    //类中的静态数据成员,所有的对象都共用这一个成员,这个静态数据成员只有一份内存在内存中
    46. getchar();
    47. getchar();
    48. return 0;
    49. }
    50. node::id;
    51. node n; n.id;

    4、静态函数成员定义

    1. class node
    2. {
    3. public:
    4.    static void fun(){}//类中定义
    5.    static void fun1()//类中声明
    6. }
    7. void node::fun1(){}//在类外定义

    5、静态函数成员的特点

    1. class person
    2. {
    3.    static int sum;
    4. public:
    5.    static int getsum()
    6.   {
    7.        return sum;
    8.   }
    9. }
    10. int person::sum=10;
    11. int main()
    12. {
    13.    cout<getsum()<//10
    14. }

    1.类中的静态函数成员,这个函数同样也不属于对象,而是属于类的,所以这个函数中不能操作类中的普通数据成员和普通函数成员。因为这些普通成员时必须要有对象的时候才会被建立,而静态函数不用对象也能调用

    2.访问和静态数据成员一样

    3.在这个静态函数成员中,不能访问这个类的普通成员,因为那些普通成员时需要有对象才会创建的,但是静态函数成员没有对象也能使用。可以在这个静态函数中使用局部变量,形参,静态数据成员

    4.一般静态函数成员是用来操作静态数据成员的,在这个函数中,我们可以操作的数据是不属于对象的数据

    6、单例模式

    1.单例模式是一种常用的软件设计模式。通过单例模式可以保证系统中,应用该模式的类只有一个实例对象

    2.单例模式的类中提供私有下的构造函数(默认,拷贝构造就够了)

    3.包含一个本身这个类的私有的静态对象

    4.提供一个静态的公有函数去创建或获取这个私有对象

    在单例模式中的类中,把构造函数写在私有属性下面(默认,拷贝)

    包含一个自身这个类类型的指针(静态)

    1. #include
    2. using namespace std;
    3. class Person
    4. {
    5. Person()
    6. {
    7. cout << "对象创建" << endl;
    8. }
    9.    
    10. Person(const Person&p){}//拷贝构造
    11. //这两个函数在私有属性下面,不能创建对象访问
    12. static Person* person;//通过创建一个静态的指针对象,来访问
    13. public:
    14. static Person* getperson()
    15. {
    16. return person;
    17. }
    18. void speak()
    19. {
    20. cout << "我是单例模式" << endl;
    21. }
    22. };
    23. Person* Person::person = new Person;
    24. //静态数据成员要在类外初始化
    25. int main()
    26. {
    27. Person* p = Person::getperson();
    28. //得到了person这个指针成员
    29. p->speak();
    30. delete p;
    31. p = NULL;
    32. getchar();
    33. getchar();
    34. return 0;
    35. }

    单例模式分为两种:

    饿汉模式:在初始化的时候就实例化了对象

    懒汉模式:在类中自己提供静态的函数来实例化对象(公有属性)

    1. class person
    2. {
    3. person()
    4. {
    5. cout << "我是懒汉模式" << endl;
    6. }
    7. static person* stance;
    8. public:
    9. static person* getperson()
    10. {
    11. if (stance == NULL)
    12. {
    13. stance = new person;
    14. }
    15. return stance;
    16. }
    17. };

    二、友元成员

    1、知识点

    1.类的特性之一就是封装,而友元就是c++为用户提供打破这种封装的手段,友元分为友元函数和友元对象

    /*
    1.我们已经知道类具备封装和信息隐藏的特性。只有类的成员函数才能访问类的私有成员,程序中的其他函数是无法访问私有成员的。
    2.非成员函数能够访问类中的公有成员,但是假如将数据成员都定义为公有的,这又破坏了隐藏的特性。
    3.另外,应该看到在某些情况下,特别是在对某些成员函数多次调用时,由于参数传递,类型检查和安全性检查等都需要时间,而影响程序的运行效率。
    */

    2、友元函数

    1.友元函数只是一个函数,友元函数不是类的成员,通过类对象是无法访问的,但是在这个函数中有权访问类中的成员

    2.友元函数,无论声明在类中的任意访问属性下都可以,不影响他的调用和访问

    1. #include
    2. #include
    3. using namespace std;
    4. class Person
    5. {
    6. int id;
    7. string name;
    8. public:
    9. Person(int id, string name)
    10. {
    11. this->id = id;
    12. this->name = name;
    13. }
    14. //声明友元函数-全局函数
    15. friend void fun();
    16. friend void fun1(Person& p);
    17. };
    18. void fun()
    19. {
    20. Person p(1, "yunfei");
    21. cout << p.id << endl;
    22. cout << p.name << endl;
    23. }
    24. void fun1(Person& p)
    25. {
    26. cout << p.id << endl;
    27. cout << p.name << endl;
    28. }
    29. int main()
    30. {
    31. Person p1(2, "feiyun");
    32. fun();
    33. fun1(p1);
    34. getchar();
    35. getchar();
    36. return 0;
    37. }

    3、友元类

    友元类是一个单独的类,只不过和友元函数一样,在类中声明了一个友元类,在这个友元类中同样也可以访问该类中的所有成员,在A类中声明B类为A类的友元类,那么在B类中就可以访问A类中所有成员

    1. #include
    2. #include
    3. using namespace std;
    4. class girlfriend
    5. {
    6. void sleep()
    7. {
    8. cout << "一起睡觉" << endl;
    9. }
    10. public:
    11. void speak()
    12. {
    13. cout << "一起说话" << endl;
    14. }
    15. //声明友元类
    16. friend class Boy;
    17. //声明了之后,Boy这个类才可以访问girlfriend里的私有属性
    18. };
    19. class Boy
    20. {
    21. girlfriend* gf;//要有这个对象才能访问girlfriend这个类
    22. public:
    23. Boy(girlfriend* gf)//构造函数
    24. {
    25. this->gf = gf;
    26. }
    27. void sport()
    28. {
    29. gf->speak();
    30. gf->sleep();//声明之后才能访问
    31. }
    32.    
    33. ~Boy()//析构函数
    34. {
    35. if (gf != NULL)
    36. {
    37. delete gf;
    38. gf = NULL;
    39. }
    40. }
    41. };
    42. int main()
    43. {
    44. Boy b(new girlfriend);
    45. b.sport();
    46.    
    47. getchar();
    48. getchar();
    49. return 0;
    50. }

    4、友元的特性

    1.单方向:B是A的朋友,B可以访问A的数据,A不可以访问B的数据

    2.不传递:A是B的朋友,B是C的朋友,A和C没有朋友关系

    3.不继承:A是B的朋友,B是C的父亲,A和C没有关系

    4.友元的作用在于提高程序的运行效率,但是他破坏了类的封装性和隐藏性,使得非成员函数能够访问类的私有成员

    三、常量成员

    1、知识点

    1.常量成员,指的是在c++类中声明对象成员时可以加上const关键字,这样声明的成员叫常量成员,常量成员分为两类:

    常量数据成员

    常量函数成员

    2、常量数据成员

    1. //定义
    2. class node
    3. {
    4.    const int id;
    5. }
    6. //初始化
    7. const int id=10;//不建议使用,有的版本可能不支持或者通过初始化列表的方式初始化,从c11以上支持定义数据时初始化

    3、初始化列表的使用

    1. #include
    2. #include
    3. using namespace std;
    4. class node
    5. {
    6. //const int id = 10;
    7. const int id;
    8. int b;
    9. public:
    10. node():id(42),b(99)//初始化列表
    11. {
    12. b = 34;//最后b=34
    13. }//先执行初始化列表,然后执行构造函数
    14.    
    15. int getid()
    16. {
    17. cout << b << endl;
    18. return id;
    19. }
    20. };
    21. int main()
    22. {
    23. node p;
    24. cout << p.getid() << endl;
    25. getchar();
    26. getchar();
    27. return 0;
    28. }

    4、初始化列表的特性

    1.初始化列表也是实现类中成员数据的初始化的一种方式

    2.一些特殊情况下,数据成员的初始化只能用初始化列表的方式给数据成员赋值,而不能在构造函数中直接赋值

    3.初始化列表必须写在构造函数的定义后面

    4.构造函数能对数据的初始化工作,初始化列表也可以,但是初始化列表能做的,构造函数不一定能做:比如常量,对象成员,引用只能在初始化列表中被初始化

    5.初始化列表的初始化顺序是按照他们在类中出现的顺序来初始化的,而不是在初始化列表中写的顺序来初始化的

    构造函数---无参构造,有参构造,拷贝构造

    5、常量函数成员

    1.定义

    1. class node
    2. {
    3.    int id=10;
    4.    public:
    5.    void fun()const
    6.   {
    7.        id=20;//报错,常量函数成员不能修改普通数据成员,只能访问
    8.        
    9.        int a;
    10.        a=10;//可以执行
    11.   }
    12.    void fun1()const;//类内声明
    13. }
    14. void node::fun1()const//类外实现
    15. {
    16.    
    17. }
    18. //在这个函数中,不能修改类中的数据成员(静态数据可以)

    2.特点

    类中的常量函数成员,在这个函数中不能对普通数据成员进行修改,通过语法限定,只要是this指针所指向的所有数据都不可以被修改(静态数据可以改变)。可以用来帮助我们来限定自身来调用这个函数修改自身的数据

    可以用来只读操作

    6、常量对象

    1.在对象实例化的时候在类名前面加上const修饰,该对象为常量对象,满足常量的操作,声明时必须初始化

    2.该对象里面的所有数据都不能被修改,因此对象里面的普通成员函数不允许被调用,只允许调用常量函数成员

    7.const引用

    不是const引用,就不能对const变量进行引用

    但是:const引用可以对非const变量进行引用

    1. void play(Man &man) {
    2. man.play();
    3. }
    4. const Man man1;
    5. play(man1);
    6. //这是错误的
    7. /*
    8. 原因:man1是const的不能被修改,而play()的形参是非const引用,所以man是可以被修改的,但是man1不能被修改所以错误
    9. 反过来,play()的形参是const引用,但是传入的参数可以是非const的
    10. */

  • 相关阅读:
    JVM-0522
    数据结构与算法之美学习笔记:52 | 算法实战(一):剖析Redis常用数据类型对应的数据结构
    大二学生HTML期末作业、个人主页网页制作作业
    Linux笔记
    AI基础:从线性回归到梯度下降
    LeetCode 面试题 02.08. 环路检测
    代码 - 多张图片合并成PDF(每页宽高即是当前页面图片的宽高)- itextpdf
    对于《数据结构与算法之美》的理解
    本地部署Ollama+qwen本地大语言模型Web交互界面
    java基于ssm房屋出售租赁管理系统
  • 原文地址:https://blog.csdn.net/m0_52559870/article/details/126165259