static
static这个关键字在c中有两个完全不相干的两种语义,在函数局部用来修饰局部变量,函数前面用来将函数的作用域限定在本文件中。为了尽可能的减少关键字,所以c++又给static定义了第三种完全不相干的语法,在类中用来修饰静态成员。
static用在成员变量,那么就是静态成员变量;static用在成员函数,那么就是静态成员方法;
static成员实例化
经过static修饰后的成员属于类本身而不属于对象,在定义对象的时候不会去实例化静态成员变量,所以需要对其进行独立定义,示例如下,静态成员函数则不需要单独初始化,因为函数实体编写在外部,本身就是一种初始化。
class person //定义一个person类
{
public:
static int a; //声明一个静态成员变量a
};
int person::a=23; //定义静态成员变量并初始化
静态数据成员不能在类中初始化,因为类型定义只是定义了一个模板。也不能在构造函数中初始化,因为静态变量是多个对象共享的,假如构造函数能初始化,那么类每创建一个对象都会改变静态成员的值,就乱套了,当然也不能用初始化列表来初始化,初始化时如果不赋初值,默认等于0。
静态成员变量访问
static成员既然是在类中,自然就遵循类的权限管理。静态成员可以单独使用“域名::成员名”来访问,也可以通过对象访问,示例如下,在定义了多个对象时,其多个对象都可以访问被声明的静态成员变量或方法,且访问的是同一个实体,被多个对象“共享”。
person::a=23; //单独访问
person p1,p2; //定义2个对象
cout<<"p1.a = "<<p1.a<<endl; //基于p1访问a
cout<<"p2.a = "<<p2.a<<endl; //基于p2操作a
想要静态修饰成员函数,只能在类中添加static,不能在外部实体函数添加,因为外部实体函数前添加static与文件内作用域功能的static冲突。
普通成员与静态成员互掉
普通成员函数可以调用静态成员变量,调用方法有如下三种,推荐使用第二种,因为第二种从语法上一看就知道是静态成员。
p1.a=23; //通过对象访问
person::a=23; //通过类名访问
this->a=23; //通过对象指针访问
静态方法只能访问静态成员和方法,不能访问任何非静态的东西。如果要非要访问可以使用函数传参方式来实现。示例如下:
p1.print(p1.b);
void person::print(int aa)
{
cout << "a = " <<aa <<endl;
}
从内存角度对比
普通成员与对象绑定,随对象的建立而建立,随对象的消亡而释放,类似于局部变量或malloc堆内存。
静态成员在链接时分配地址,程序加载时被建立,程序结束时消亡,等同于全局变量。静态成员函数也遵循该规则,类似于全局函数。
静态成员变量在对象中不占用存储空间,只是一个申明,他的内存空间与全局变量在一个区域。
静态成员的用途
静态成员是与类相关的,是一种类的行为,而不是与该类实例的对象相关,例如我们抽象一个类来描述一个学生,一个对象代表一个学生,而对所有学生的统一描述如学生人数、平均成绩等,放在对象中显然不合适,适合用静态成员变量来记录,对静态成员进行操作的函数就适用静态函数来描述,实现代码如下示例:
/*
*每个学生用一个对象来表达,使用静态成员来实现学生人数统计
*/
#include<iostream>
using namespace std;
class student
{
public:
static int num; //学生人数,静态成员声明
static void print(void); //打印人数,静态成员声明
student(string n,int a); //类的构造函数
~student(); //析构
private:
string name; //姓名
int age; //年龄
};
int student::num; //静态成员变量定义
void student::print(void) //函数实体
{
cout << "student num: " << student::num << endl;
}
student::student(string n,int a) //构造函数
{
name = n;
age =a;
student::num++;
}
student::~student() //析构函数
{
student::num--;
}
int main(void)
{
student s1("hanmei",18); //实例化对象
student s2("lilei",17); //实例化对象
student::print(); //打印数量
return 0;
}
静态成员与面向对象
静态成员仍然在class内,仍可通过对象调用,表面上是遵守了面向对象的规则。实际上静态成员一定程度的破坏了面向对象,即使没有对象仍然可以单独访问到静态成员。
静态成员变量其实就是将全局变量封装到了类中,以方便访问。
静态成员和非静态成员完全不同,两个唯一的共同点就是都被包含在了同一个类中。
静态类
什么是静态类
class中所有的成员都是静态成员,那么这个类就成了一个静态类,这些静态类全部都需要进行外部定义,类中其实是空的,所以静态类不能实例化对象,没有对象,class的很多操作都不能有,例如,不能被继承、不能有protected、不能指定任何接口实现,不能有普通构造函数,但是可以有静态构造函数,来分配初始值或设置某个静态状态。
密封(sealed)
静态类不能被继承,这一特性间接的实现了对类的密封(sealed),在java等高级语言中,源支持密封,虽然c++不支持,但是可以使用静态类来间接实现。由于类都有构造函数,有了构造函数,被调用时就有可能去实例化对象,语法规定又不能没有构造函数,解决方法就是将构造写在private下。
小结
静态类实际上使用得比较少,所以没有展开讲。而静态成员在c++中略显尴尬,即使没有静态成员,使用全局变量一样可以完成功能,这跟静态局部变量有些像,静态局部变量其实也可以使用全局变量来替代,只不过静态局部变量的作用域不同,只能在函数内部访问,但是又具有全局变量的特性。静态成员也是这各道理,具有全局变量的特性,但是作用域又只能基于类访问,将全局变量与。