C++ 中的 static & const关键字

C++ const & static 关键字

const

用法1 : 修饰基本数据类型

1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include <string>

// 程序的主函数
int main( )
{
const int a = 5;
a = 3; // this is a error
return 0;
}

用法2 : const修饰指针变量*及引用变量&

2.1 : 指针*

1
2
3
4
const int* a = & [1]          //非常量数据的常量指针    指针常量
int const *a = & [2] //非常量数据的常量指针 a is a pointer to the constant char variable
int* const a = & [3] //常量数据的非常量指针指针常量 常量指针 a is a constant pointer to the (non-constant) char variable
const int* const a = & [4] //常量数据的常量指针
  • 如果const位于星号*的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;
  • 如果const位于星号*的右侧,const就是修饰指针本身,即指针本身是常量。
  • 因此,[1]和[2]的情况相同,都是指针所指向的内容为常量,这种情况下不允许对内容进行更改操作,如不能*a = 3 ;
  • [3]为指针本身是常量,而指针所指向的内容不是常量,这种情况下不能对指针本身进行更改操作,如a++是错误的;
  • [4]为指针本身和指向的内容均为常量。

2.2 : 引用&

1
2
3
int const &a=x;
const int &a=x;
int &const a=x;//这种方式定义是C、C++编译器未定义,虽然不会报错,但是该句效果和int &a一样。
  • 这两种定义方式是等价的,此时的引用a不能被更新。如:a++ 这是错误的。

用法3 : const应用到函数中

3.1 : 作为参数的const修饰符

  • void fun0(const A* a ); void fun1(const A& a)
  • 调用函数的时候,用相应的变量初始化const常量,则在函数体中,按照const所修饰的部分进行常量化,如形参为const A* a,
  • 则不能对传递进来的指针的内容进行改变,保护了原指针所指向的内容;如形参为const A& a,则不能对传递进来的引用对象进行改变,保护了原对象的属性。
  • [注意]:参数const通常用于参数为指针或引用的情况;

3.2 : 作为函数返回值的const修饰符

  • const A fun2( ); const A* fun3()
  • 这样声明了返回值后,const按照”修饰原则”进行修饰,起到相应的保护作用。
  • 返回值不可以被修改

3.3 : 配合 class 使用

  • 不能修改所在类的的任何变量
  • mutable 关键字
    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
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    #include <iostream>

    class Entity
    {
    private:
    int m_X;
    int* m_Y;

    // 加入一个小插曲
    int* m_Z, m_M; // 这两个值中,第一个 m_Z 是指针,而第二个是 int 数,需要改成 int* m_Z, *m_M; 这样两个都是指针

    mutable int var;
    public:
    // 这种 const 用法只可以在 class 的 function 中使用
    int GetX() const
    {
    m_X = 34; // error, 无法修改其值
    var = 1; // mutable 关键字修饰,就可以进行修改
    return m_X;
    }

    // 返回一个 int 指针,其指向 & 具体数值都不可以改变
    // 最后一个 const 表示无法在函数中修改值
    const int* const GetY() const
    {
    return m_Y;
    }

    int* GetZ()
    {
    return m_Z;
    }
    };

    // 此处函数对 e 进行只读操作,传入 const reference, 无需拷贝
    void Print(const Entity& e)
    {
    std::cout << e.GetX() << std::endl;
    std::cout << *e.GetY() << std::endl;
    std::cout << *e.GetZ() << std::endl; // error, 因为传入的 e 是 const,因此只只可以调用 GetX,GetY
    }

    // 程序的主函数
    int main( )
    {
    Entity e;

    std::cin.get();
    return 0;
    }

其他用法

class 中使用 const

  • 对const成员变量的初始化,不能在变量声明的地方,必须在类的构造函数的初始化列表中完成,即使是在构造函数内部赋值也是不行的。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class Test
    {
    private:
    const int a;
    const int b;
    public:
    Test(int a)
    :a(a), b(12)
    {
    }
    }

使用static const

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>

class Year
{
private:
int y;
public:
static int const Inity;
public:
Year()
{
y=Inity;
}
};

int const Year::Inity=1997;//静态变量的赋值方法,注意必须放在类外定义

int main()
{
std::cout << Year::Inity << std::endl;//注意调用方式,这里是用类名调用的。
}

static

  • static 可以修饰 变量 & 函数
  • static 可以出现在 class内部 & class外部

在 class/struct 内部

  • static修饰的 类成员(包括变量 & 函数) 属于类,不属于对象

修饰类中成员 - 类的共享数据

  • static类对象必须要在类外进行初始化
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    #include <iostream>
    using namespace std;

    class Entity{
    public:
    static int x;
    void print()
    {
    cout << x << endl;
    }
    };

    int Entity::x; // static类对象的初始化

    int main()
    {
    Entity e1;
    Entity e2;

    e1.x=1;
    e2.x=2;
    e1.print();
    e2.print();
    }

修饰类中成员函数

  • 由于static修饰的类成员属于类,不属于对象,因此static类成员函数是没有this指针的,this指针是指向本对象的指针。
  • 正因为没有this指针,所以static类成员函数,不能访问非static的类成员,只能访问 static修饰的类成员。

在 class/struct 外部

  • 表示只在当前的编译单元引用

static 出现在 .cpp 文件中

  • 在demo1.cpp中

    1
    static int x = 7;
  • 在demo2.cpp中

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #include <iostream>
    using namespace std;

    int x;

    function main()
    {
    cout << x << endl;
    }
  • 编译的时候就会报错,因为x只在demo1.cpp中才可以被使用

  • 类似的,function 和 var 有类似的用法,static 的 function 只可以在当前的解释单元被使用

static 出现在 .h 文件中

  • 如果在 头文件 中申明 static变量
  • 那么每一个include的文件都会有一个单独的 static 变量,因为 include 就相当于将这段代码copy进去

局部 static变量

  • 主要关注点变量的生命周期
  • 注意 static 关键字在 function 中的用法

demo1

1
2
3
4
5
6
function test()
{
static int x = 0; // 静态局部变量
x++;
cout << x << endl;
}
  • x变量只会创建一次
  • 每次调用test函数,x都会增加,打印的值也会增加
  • 静态局部变量在全局/静态区分配内存空间
  • 静态局部变量在程序执行到该对象的声明处时被首次初始化,之后的函数调用不再进行初始化
  • 静态局部变量一般在声明处初始化,若没有显式初始化,会被OS自动初始化为0
  • 它始终驻留在全局/静态区,直到程序运行结束,但其作用域为局部作用域,也就是不能在函数体外面使用它

Tips

  • 全局数据中的变量 如果没有显示的初始化会自动被程序初始化为0(这个特性非静态全局变量也有),而在函数体内声明的变量如果不显示初始化则会使一个随机值