const 与 static

183 阅读3分钟
  • const

    • 就是将对象修饰为 常量 类型,就是不可修改类型,比如
      • const int* p; : const 修饰的是 p 指向的那块内存,p 可以重新赋值,但是 *p 不能
      • int const* p; : const 修饰的是 p 指向的那块内存,p 可以重新赋值,但是 *p 不能,跟上面一样
      • int* const p; : const 修饰的是 p 的地址,p 不可以重新赋值,但是 *p 可以
    • 如果函数的形参是 const 类型,则这个参数不能被修改,一般用来保护传进来的对象不被本函数篡改
    • const 类型的变量在离开作用于后会被释放
    • 如果类成员变量是 const 类型,则需要在构造函数的初始化列表定义,要求一定要有构造函数,比如
    class Test
    {
    public:
    	Test() : m_nId(0) {}
    private:
    	const int m_nId;
    };
    
    • 之所以需要在构造函数的初始化列表定义,是因为 const 成员变量对于类来说是不存在的,其只存在于对象的生存期,也就是说类只有实例化成对象了,这个 const 类成员对象才是一个常量,所以不能在类声明的地方定义,因为此时类还没实例化
    • 如果类成员函数是 const 类型,那么在这个函数内,不能修改类成员变量,其实就是将 this 指针修饰为 const
    • const 成员函数不能调用非 const 成员函数,因为在类成员函数的形参列表里,其实隐式塞入了一个 this 指针,如果是 const 的成员函数,那么这个指针的类型就是 const T* this,但是非 const 成员函数的指针类型是 T* this,两者不匹配,所以无法调用。燃鹅,非 const 成员函数可以调用 const 成员函数,因为 C++ 里有个最小权限原则,我的理解是,非 const 权限大,const 权限小,小的不能调用大的,大的能调用小的
    • const 对象不能调用非 const 成员函数,非 const 对象可以调用 const 成员函数,原理同上
    • 类成员函数中有两个地方可以填上 const
      • 函数名前,表示返回的值是 const
      • 函数名后,表示这个函数是 const,也就是上面说的 const 成员函数
    • const 来修饰对象有两种情况
      • 对象为基本类型,在编译时,直接用常量来替换,比如下面代码,在编译 cout << a << endl; 时,编译器已经将 a 优化为 1,也就是 cout << 1 << endl;,虽然此时 a 所在的内存的值为 2
      const int a = 1;
      int* p = const_cast<int*>(&a);
      *p = 2;
      cout << a << endl; // 1
      cout << *p << endl; // 2
      
      • 对象为结构体或类,编译时,先用一个内存地址替换,比如下面代码
      struct Test
      {
          int a;
          Test() : a(1) {}
      };
      
      const Test t;
      const int b = 2;
      int* p1 = const_cast<int*>(&t.a);
      int* p2 = const_cast<int*>(&b);
      *p1 = 100;
      *p2 = 200;
      cout << t.a << endl; // 100,因为是结构体,通过地址取的,所以值变了
      cout << b << endl; // 2,基本类型,被优化成常量了
      
  • static

    • static 变量默认初始化为0,存在 .data
    • 全局静态变量,只能本文件访问,其他文件无法访问,但可以命名一个跟他一模一样的全局静态变量
    • 局部静态变量,在函数结束后不会被释放,下次再进入这个函数时,维持上一次的值
    • 静态函数,跟静态全局变量一样,只能本文件访问,其他文件无法访问
    • 对于类而言
      • 静态成员变量
        • 属于类,不属于对象,对于该类所实例化出来的对象而言,静态成员是被所有对象共享的,内存里只有一份,因为这些静态成员变量是存在 .data 段,而不是对象所在的堆或栈
        • 类里有静态成员变量,需要在类外进行定义,比如
        class Test
        {
        private:
            int m_nStatic;
            
        public:
            static void DoTest(){}
        };
        
        int Test::m_nStatic = 1;
        
      • 静态成员函数
        • 没有 this 指针,所以类里不能出现 const static 的成员函数,同时也不能为虚函数
        • 没有 this 指针,不能直接访问,需要 Test::DoTest(); 这样来访问
        • 这类的函数不能访问非静态的成员函数,如果真要访问,只能在形参里手动添加对象指针或引用,访问非静态成员变量也是如此