重点
- 静态类(sealed+abstract)
- 静态构造函数(无参,无限制符,自动执行一次)
- 静态变量(类级别,实例无关,静态存储区中)
- 静态方法(不能被重写)
- 静态局部变量(始终存在)
静态本质是实例无关的,表示不会修改实例的
C++
静态成员变量
- 静态成员 的内存只被分配一次,会一直存在于程序的整个生命周期中。
- 如果要将静态成员在类内初始化,那么该变量需要声明为const常量。
- int class :: c = 10; static数据成员可以在类外定义和初始化,也可以在函数中赋值。可以直接由 class::member 访问,但是不能用 .访问
静态成员函数
- 成员函数、静态成员函数、虚函数
在c++中类的成员函数都是保存在静态存储区中的,都是通过函数地址来访问。 - 不能调用non-static函数,但是可以通过引用传递间接调用
- 为什么静态成员函数不能是const?const修饰符用于表示函数不能修改成员变量的值,该函数必须是含有this指针的类成员函数,函数调用方式为thiscall
而类中的static函数本质上是全局函数,不能访问非静态成员,const函数表明不会修改实例成员,那么static就没意义了
静态全局变量和函数
修饰全局变量时,表明一个全局变量只对定义在同一文件中的函数可见。
修饰函数时,表明该函数只能在同一文件中调用。
static const
常量+只在当前模块中可见
C++中const是实例成员,不能在类定义处初始化,不同对象可以不同(构造初始化列表),不能由类名直接访问
C#中的const是隐式static的,可以由类名直接访问。C++const更接近于只读,所以两者的const是不同的
C#
静态类
- 静态类的本质,是一个抽象的密封类,所以不能被继承,也不能被实例化。
- 静态类与非静态类的重要区别在于静态类不能实例化,也就是说,不能使用 new 关键字创建静态类类型的变量。也不能有非静态成员(即实例成员)
- 不支持继承,所以静态类不能包含protected成员。但是可以实现接口。interface不能是静态的
- 静态类通常是收集一些常用的方法,与面向对象无关了
执行顺序(经过测试)
静态初始化器-静态构造函数-初始化器-构造函数
静态构造函数
- 这个类的成员,第一次被访问之前,会执行静态构造函数。如类被实例化或者静态成员被调用的时候进行调用,并且是由.net框架来调用静态构造函数来初始化静态成员变量。
- 静态构造函数只被执行一次。
- 静态构造函数不可被访问限制符修饰, 因为静态构造函数不是我们程序员调用的,是由.net 框架在合适的时机调用的。
- 静态构造函数没有参数,因为框架不可能知道我们需要在函数中添加什么参数,所以规定不能使用参数。
- 一个类中只能有一个静态构造函数。
- 无参数的静态构造函数和无参数的构造函数是可以并存的。因为他们一个属于类级别,一个属于实例级别,并不冲突。
- 如果我们在类中定义了静态变量,但是又没有定义静态构造函数,那么框架也会自动生成一个静态构造函数以初始化类。
静态与初始化器
- 初始化器:即声明字段后直接用=赋值
- 系统默认的初始化会将会在所有代码执行前把一切都设置成0或者null,所以这时无需用初始化器
- 静态构造函数在标准构造函数之前运行
静态成员
- 非静态类可以包含静态的方法、字段、属性或事件;
- 无论对一个类创建多少个实例,它的静态成员都只有一个副本;
- 静态方法和属性不能访问其包含类型中的非静态字段和事件,并且不能访问任何对象的实例变量;
- 可以在静态方法中定义变量并使用,和普通方法一样
- 静态方法只能被重载,而不能被重写,因为静态方法不属于类的实例成员
- 常量本质是静态的:虽然字段不能声明为 static const,但 const 字段的行为在本质上是静态的。这样的字段属于类,不属于类的实例。因此,可以同对待静态字段一样使用 ClassName.MemberName 表示法来访问 const 字段;
- 可以用 static readonly(只读不同于常量)
- this/base 关键字在静态方法中不能使用,因为有可能对象还不存在。
- 类加载的时候,所有的静态成员就会被创建在“静态存储区”里面,一旦创建直到程序退出,才会被回收。
注:Person p; //这样实际上就已经被加载了。
其他类可以直接 类名.静态变量名 来访问,就像静态类一样
静态局部变量
C++
函数中的局部变量的值在函数调用结束后不消失而保留原值,即其占用的存储单元不释放,在下一次该函数调用时,该变量保留上一次函数调用结束时的值。
为静态局部变量赋初值是在编译时进行值的,即只赋初值一次,在程序运行时它已有初值。以后每次调用函数时不再重新赋初值而只是保留上次函数调用结束时的值。
C#
c#不支持方法内的静态变量,原因有二。
1. 一般来说方法内的静态变量可以用该方法所属类的静态成员变量代替
2. 方法中的静态变量会在多线程的应用里造成不比要的麻烦。
其他
C#:不要把 static 成员变量的初始化动作安排在类的构造函数中,因为构造函数可能一再被调用,而变量的初值却只应该设定一次。
C++:也不要把初始化动作安排在头文件中,因为它可能会被包含许多地方,因此也就可能被执行许多次。你应该在实现文件中且类别以外的任何位置设定其初值。例如在 main 之中,或全域函数中,或任何函数之外