• C++回顾<二>:类-this指针-构造函数-析构函数-隐式/显式调用explicit-初始化列表 -static静态成员变量/函数-常对象|常函数


    1.访问 类中私有属性

    • 类外 对象访问 类中私有属性的方式:使用公开的set()get()方法
    class Person
    {
    //私有访问权限
        private:
                string name;
                int age;
    //公有访问权限
        public:
                void work()
                {
                    cout << "正在努力的工作" << endl;
                }
                string getName()   // 获取
                {
                    return name;
                }
                void setName(string _name)  // 设置
                {
                    this->name  = _name;
                }
    };
    int main()
    {
                Person p;                    		//在栈区使用Person类定义对象
                Person* pa = new Person;    	//在堆区使用Person类定义对象。
    
                pa->setName("zhangsan");    // 设置
                pa->work();                 // 正在努力的工作
                cout << pa->getName() << endl; // 获取
                delete pa;
                return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    2.类或对象的内存大小

    • class 定义的的类与C中字节对齐是一致的。类中的成员函数不占用类或对象的空间。

      class A
      {
          public:           // 属性才占用空间
                  int a;        // 4字节 只有int a时 sizeof (A)=4
                  double b;     // 8 字节            sizeof (A)=16
                  void show()   // 不占用空间 ;
                  {
                      cout << "hello" << endl;
                  }
      };
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10

    3.this本对象的指针

    • 类中static修饰静态成员函数不可以使用this指针(没有this)
    • 类中 普通成员函数 可以使用this指针 --> 类中static修饰的变量
    • 这个this被 编译器默默地 放在了 成员函数参数列表的首位置
        class Stu
        {
            private:
                string name;
            public:
                //返回本对象。
                Stu& setName(const string& name)
                {
                    this->name = name;
                    //返回本对象
                    return *this; // 指针指向Stu
                }
        };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    4.构造函数|析构函数

    class A{
    		int* p;
        public:
    		A( ) = default;// 构造函数 ,默认构造
                    A()
                    {	
                        this->p = new int[1024];
                    }   // 构造函数
    		~A()
            	{	
    			delete []p;
            	}   // 析构函数
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    构造函数

    • 函数名与类名相同,没有返回值,连void都没有。
    • 构造函数也会根据参数列表中的参数类型个数不同形成重载关系。
    • 构造函数是给C++编译器调用的。
      • 生成时机:
        1. 如果类中没有定义任何 自定义的构造函数,编译器就会的提供一个默认的构造函数。
        2. 如果类中提供任何一个自定义的构造函数,编译器就不再提供任何默认的构造函数。

    析构函数

    • 析构函数的意义: 就是用来 释放类中属性指针,指向堆区空间的。
    • 类对象被销毁时,编译器自动调用析构函数
    • 一个类中可以有多个构造函数,只能有一个析构函数 (堆区空间不能多次释放)

    5.隐式调用及显式调用explicit

    • A a2 = 10; 隐式调用

    • A a2(20); 显式调用 用意:提高代码的可读性,维护。

        class A
        {
                int num;
        public:
                A()
                {
                        cout << "A()" << endl;
                }
                // 必须显式调用
                explicit A(int _num)     //指定编译器调用此构造时,必须显式调用。用意:提高代码的可读性,维护。
                {
                        this->num = _num;
                }
        };
        int main()
        {
                A a;         		//调用的无参空构造
                A a1(10);    		//调用的有参的构造
                A a2 = 10;		//隐式调用。
    
                // 以下 都是 显式调用
                A a2(20);
                A* pa = new A;
                A* pa1 = new A();
                return 0;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    6.初始化列表

    • 类中有const修饰的类型变量时,使用初始化列表来进行初始化。

    • 构造函数的初始化列表是构造函数的特殊语法,所以只在构造函数中使用

    • 构造函数的(): 类中属性变量(初值),类中属性变量2(),...

    • 初始化列表的初始化的顺序:按照类中属性声明的顺序依次进行初始化。

    • 初始化列表的调用时机:开辟空间之后,编译器调用的初始化列表,然后再调用的构造函数。

    • 类中 定义其他类对象 需要 在初始化列表中初始化

        class B
        {
            public:    // 公有
                int number;
            public:    // 公有
                explicit B(int _number) //explicit关键字 显式调用指定
                {
                    this->number = _number;
                }
        };
    
        class A
        {
            public:        // 公有
                const int number;    
                const int age;
                int efg;
                string name;	// 可以初始化,也 可以不初始化
                B b;                    // 类 定义对象 要在初始化列表中,初始化
            public:        // 公有
                A():number(10),age(88),name("zhansan"),b(B(10))        // 初始化列表方式及初始化顺序
                {
                    cout << "A的无参空构造" << endl;
                }
    
                A(int a, int b):number(10),age(88),name("zhansan"),b(B(10))
                {
                    efg = b;
                }
        };
        int main()
        {
            A a;                       
            A a1(15,16);                 
            return 0;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    7.static静态数据

    静态成员变量

    • 在C中使static修饰的成员变量,系统会为进程分配一个0-4G的内存空间

    在这里插入图片描述

    • 当一个进程被加载时,系统会首先加载静态区数据
    1. **文件代码段:**编译好的机器码,内容即是 一个个函数机器码 及 保存函数地址的指针。

    2. rodata段:全局只读数据,比如:全局const修饰的变量或字符串。

    3. data段: 已初始化的全局变量static修饰且初始化的变量

      (data段数据 将 在程序执行前 系统调用copy_data()函数 向程序中拷贝一分副本)

    4. bss段: 未被初始化的全局变量,或局部定义使用static 修饰的静态变量

      (bss段数据 在程序执行前 系统会调用bss_clear()函数 对其进行初始化)

    • 当用static在类中修饰一个成员变量时,由于类中定义的static是隐藏在类中,系统无法调用bss_clear()直接进行初始化。

      1. 所有C++语法规定,当系统加载时,必须要在类外对static修饰的成员变量进行首次初始化
      2. 如果没有在类外对static修饰的成员变量进行初始化,那么此变量在类中仅为一个声明,而没有定义。当对象引用这个成员变量时就会发生链接错误。
          class Stu
          {
              private:
                      string name;
              public:
                  static int count;		//	static修饰的变量,只生成一份。因为他在静态区,进程空间对静态区只开辟一次。
                  				      //    而且这一份静态空间 是所有使用Stu类的对象的共享的一份。
                  				      //    static修饰的变量或对象,是属于整个进程的,只不过是隐藏在了类域之中。
                  				     //     所以需要在类外的 全局区 进行初始化。
                  //所以static修饰的变量或对象,是属于整个类的,可以使用类名 : : 的方式直接访问。
                 Stu() = default;//默认构造
                 Stu(string name)
                 {
                     this->name = name;
                     this->count++;			//记录count的值。
                 }
          };
          //static 修饰的类中的属性的初始化的语法格式。
          int Stu::count = 0;
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
    • 由于,静态区数据只会由进程加载一次,在静态区的类成员数据,是所有对象的共享部分。

      也就是所有对象都共享这份数据,当这份数据被修改时,所有对象中的这分共享部分都将被修改。

    • 由于静态成员变量定义在静态区内存,而对象(类)是存在于动态区之中,所以静态成员变量并不占用类对象的内存空间

    • 由于类中静态成员变量,是属于整个进程的,进程执行前就已经在静态区存储,而类对象是在动态区的,所以此成员不依赖于某个类对象的,它是属于整个进程的,

      ​ 因为他又隐藏于类中,所以我们可以使用 类域访问 的形式对直接访问。(等于有 类内的访问权限的限制。)

      类名 ::静态成员函数

    静态成员函数

    • static修饰的成员函数称为静态成员函数。static修饰的成员变量,称为静态成员变量

      1. 普通成员函数 是 可以调用 类中的静态成员变量

      2. 普通成员对象 是 可以调用 类中的静态成员函数

      3. 但是static修饰成员函数不可以访问类中的非静态属性的。因为它 没有this指针。只能访问类中的 静态属性

      4. static修饰的变量,是服务于整个类,static修饰的成员函数,也是服务于整个类的

        底层逻辑

        使用static修饰成员函数与修饰变量不同,并不是对存储方式的修饰,而是将此成员函数提升为全局函数的特性。由于全局函数中的形参是定义在全局数据段的,所以没有this指针,所以是没有办法调用到类中的成员的。所以类中的静态成员函数是 不可访问普通成员变量或函数的。

      5. 普通成员对象或函数 是 可以访问 静态成员变量调用静态函数

      	static int count;		//  静态成员变量, 在静态区, 需要在类外的 全局区 进行初始化
              static int getCount()	//   静态成员函数, 成员函数提升为全局函数;没有this指针,
              {
                      return count;
              }
      
       //这就是静态函数的意义向在。无需依赖于某一个对象。 类名 :: 全局函数
          cout << Stu::getCount() << endl;
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

    8.常对象|常函数

    • const修饰 的对象 叫常对象,const修饰 的函数 就是常函数
    • 常对象,不可以调用类中的普通成员函数,常对象 只能调用 常函数。因为类中的普通成员函数是有this指针,通过this指针是调用或修改类中的属性的,程序设计的安全性,常对象 只能调用 常函数
    • 普通对象可以调用常函数的。常函数 中是 不可以 对类中的属性进行 写操作,只能 读操作
            void setName(string name)	// 类中 普通成员函数
            {
                this->name = name;
            }
    	string getName( )const  		//类中 常函数
            {
                    //this->name = "gaowanxi"; //const修饰的函数是不可以对类内属性进行 写操作的。
                    return this->name;
            }
    					// 常对象
    	void showInfo(const Stu stu)
            {
               //stu.setName("zhangshan"); 			// 常对象是不可调 用类中的成员函数的。
                cout << stu.getName() << endl;		//常对象 只能调用 常函数。
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
  • 相关阅读:
    Redis 主从复制的原理
    Java高级特性-泛型类型推断
    第02章 BeautifulSoup 入门
    #循循渐进学51单片机#变量进阶与点阵LED#not.6
    【算法】冒泡排序
    pandas - merge()
    git流水线(Pipeline)导致分支(Branch)无法合并的解决方法
    HTTP 请求行
    低代码+知识管理,打造智能化供应链管理系统
    创建vue项目教程
  • 原文地址:https://blog.csdn.net/qq_47355554/article/details/126167430