在类内成员变量的声明前加上关键字static,该数据成员就是类内的静态数据成员。
#include <iostream.h> class Myclass { public: Myclass(int a,int b,int c); void GetSum(); private: int a,b,c; static int Sum;//声明静态数据成员 }; int Myclass::Sum=0; //定义并初始化静态数据成员 Myclass::Myclass(int a,int b,int c) { this->a=a; this->b=b; this->c=c; Sum+=a+b+c; } void Myclass::GetSum() { cout<<"Sum="<<Sum<<endl; } void main() { Myclass M(1,2,3); M.GetSum(); Myclass N(4,5,6); N.GetSum(); M.GetSum(); }
静态成员变量有以下特点:
class CMyclass{ int n; static int s; }; //则sizeof(CMyclass)等于4
设置静态成员(变量和函数)这种机制的目的是将某些和类紧密相关的全局变量和函数写到类里面,看上去像一个整体,易于理解和维护。如果想在同类的多个对象之间实现数据共享,又不要用全局变量,那么就可以使用静态成员变量。也即,静态数据成员主要用在各个对象都有相同的某项属性的时候。比如对于一个存款类,每个实例的利息都是相同的。所以,应该把利息设为存款类的静态数据成员。这有两个好处:
你也许会问,用全局变量不是也可以达到这个效果吗?
同全局变量相比,使用静态数据成员有两个优势:
与静态成员变量类似,我们也可以声明一个静态成员函数。
静态成员函数为类服务而不是为某一个类的具体对象服务。静态成员函数与静态成员变量一样,都是类的内部实现,属于类定义的一部分。普通成员函数必须具体作用于某个对象,而静态成员函数并不具体作用于某个对象。
普通的成员函数一般都隐含了一个this指针,this指针指向类的对象本身,因为普通成员函数总是具体地属于类的某个具体对象的。当函数被调用时,系统会把当前对象的起始地址赋给 this 指针。通常情况下,this是缺省的。如函数fn()实际上是this->fn()。
与普通函数相比,静态成员函数属于类本身,而不作用于对象,因此它不具有this指针。正因为它没有指向某一个对象,所以它无法访问属于类对象的非静态成员变量和非静态成员函数,它只能调用其余的静态成员函数和静态成员变量。从另一个角度来看,由于静态成员函数和静态成员变量在类实例化之前就已经存在可以访问,而此时非静态成员还是不存在的,因此静态成员不能访问非静态成员。
//Example 6 #include <iostream> using namespace std; class Student{ private: char *name; int age; float score; static int num; //学生人数 static float total; //总分 public: Student(char *, int, float); void say(); static float getAverage(); //静态成员函数,用来获得平均成绩 }; int Student::num = 0; float Student::total = 0; Student::Student(char *name, int age, float score) { this->name = name; this->age = age; this->score = score; num++; total += score; } void Student::say() { cout<<name<<"的年龄是 "<<age<<",成绩是 "<<score<<"(当前共"<<num<<"名学生)"<<endl; } float Student::getAverage() { return total / num; } int main() { (new Student("小明", 15, 90))->say(); (new Student("李磊", 16, 80))->say(); (new Student("张华", 16, 99))->say(); (new Student("王康", 14, 60))->say(); cout<<"平均成绩为 "<<Student::getAverage()<<endl; return 0; } 运行结果: 小明的年龄是 15,成绩是 90(当前共1名学生) 李磊的年龄是 16,成绩是 80(当前共2名学生) 张华的年龄是 16,成绩是 99(当前共3名学生) 王康的年龄是 14,成绩是 60(当前共4名学生) 平均成绩为 82.25
调用静态成员函数,两种方式:
在使用包含静态成员的类时,有时候会调用拷贝构造函数生成临时的隐藏的类对象,而这个临时对象在消亡时会调用析构函数有可能会对静态变量做操作(例如total_num–),可是这些对象在生成时却没有执行构造函数中的total_num++的操作。解决方案是为这个类写一个拷贝构造函数,在该拷贝构造函数中完成total_num++的操作
在全局变量前,加上关键字static,该变量就被定义成为一个静态全局变量。
/Example 1 #include <iostream.h> void fn(); static int n; //定义静态全局变量 void main() { n=20; cout<<n<<endl; fn(); } void fn() { n++; cout<<n<<endl; } 结果: 20 21
static int n; //定义静态全局变量
改为
int n; //定义全局变量
程序照样正常运行。
定义全局变量就可以实现变量在文件中的共享,但定义静态全局变量还有以下好处:
将上述示例代码改为如下:
//Example 2 //File1 #include <iostream.h> void fn(); static int n; //定义静态全局变量 void main() { n=20; cout<<n<<endl; fn(); } //File2 #include <iostream.h> extern int n; void fn() { n++; cout<<n<<endl; }
编译并运行Example 2,会发现上述代码可以分别通过编译,但运行时出现错误。 这就是因为静态全局变量不能被其它文件所用,即使在其它文件中使用extern 进行声明也不行。
我们将
static int n; //定义静态全局变量
改为
int n; //定义全局变量
再次编译运行程序,程序可正常运行。
因此,在一个文件中,静态全局变量和全局变量功能相同;而在两个文件中,要使用同一个变量,则只能使用全局变量而不能使用静态全局变量。
在局部变量前,加上关键字static,该变量就被定义成为一个静态局部变量。
//Example 3 #include <iostream.h> void fn(); void main() { fn(); //10 fn(); //11 fn(); //12 } void fn() { static int n=10; cout<<n<<endl; n++; } 结果: 10 11 12
通常,在函数体内定义了一个变量,每当程序运行到该语句时都会给该局部变量分配栈内存。但随着程序退出函数体,系统就会收回栈内存,局部变量也相应失效。
但有时候我们需要在两次调用之间对变量的值进行保存。通常的想法是定义一个全局变量来实现。但这样一来,变量已经不再属于函数本身了,不再仅受函数的控制,这给程序的维护带来不便。
静态局部变量正好可以解决这个问题。静态局部变量保存在全局数据区,而不是保存在栈中,每次的值保持到下一次调用,直到下次赋新值。
静态局部变量有以下特点:
在函数的返回类型前加上static关键字,函数即被定义为静态函数。静态函数与普通函数不同,它只能在声明它的文件当中可见,不能被其它文件使用。
//Example 4 #include <iostream.h> static void fn();//声明静态函数 void main() { fn(); } void fn()//定义静态函数 { int n=10; cout<<n<<endl; }
定义静态函数的好处:(类似于静态全局变量)
参考(static)