1.静态数据成员
在类中,有些属性不是类中每个对象分别拥有的,而是共有的。这些共有的属性有些是变化的,如类对象创建的计数值,有些是不变的,如日期类中要用到的12个月的名称。
这些属性不能作为全局变量,因为它们是专属于某个类的。
同时这些属性页不应该是数据成员,因为不能让每个对象都单独拥有它。
对于下列代码:
#include <iostream> #include <string> using namespace std; class Student { int n; string name; public: void set(string str) { static int number = 0; name = str; n = ++number; } void print() { cout << name << " -> students are " << n << " numbers" << endl; } }; void fn() { Student s1; s1.set("Jenny"); Student s2; s2.set("Randy"); s1.print(); } int main() { Student s; s.set("Smith"); fn(); s.print(); return 0; }
输出为:
Jenny -> students are 2 numbers Smith -> students are 1 numbers
从输出的结果可以看出,结果和我们预期的不同。这主要是由于不同的对象有不同的数据成员n值所致。
?
那么这个时候需要将学生计数的变量设计为静态成员。这样保证每一个类只有一个实体,每个对象中不再有它的副本。代码实现如下:
#include <iostream> #include <string> using namespace std; class Student { static int number; string name; public: void set(string str) { name = str; ++number; } void print() { cout << name << " -> students are " << number << " numbers" << endl; } }; int Student::number = 0; void fn() { Student s1; s1.set("Jenny"); Student s2; s2.set("Randy"); s1.print(); } int main() { Student s; s.set("Smith"); fn(); s.print(); return 0; }
该代码输出如下:
Jenny -> students are 3 numbers Smith -> students are 3 numbers
数据成员设计成静态数据成员后,该成员的变化仍然会在每次对象创建之后的名称赋值后反映出来。该结果存放在专属于Student类名空间的全局数据区中,而不再属于各个Student对象。整个类中只有一份number拷贝,所有对象共享这份拷贝。因此,访问的是唯一的静态数据成员,它不会因对象而异。
?
由于静态成员脱离对象而存在的性质,所以该实体应在所有对象产生之前存在,因此,在程序启动的时候,需要先对其进行初始化。
?
定义静态成员的格式不能重复static关键字(int Student::number = 0;)但必须在成员名钱冠以类名加域caozuofu.html" target="_blank">操作符,以表示该成员的类属。如果不将其初始化,系统将为该成员清0。
?
2. 静态成员函数
由于如果把静态成员变量设置为公有类型的话,外部就可以直接访问该静态成员变量,这样有失安全性和可维护性,因此与数据成员一样,将静态成员做成私有的,用静态成员函数去访问静态数据成员是适合的。
#include <iostream> #include <string> using namespace std; class Student { static int number; string name; public: void set(string str) { name = str; ++number; } static void print_number() { cout << number << " total numbers" << endl; } void print() { cout << name << " -> students are " << number << " numbers" << endl; } }; int Student::number = 0; void fn() { Student s1; s1.set("Jenny"); Student s2; s2.set("Randy"); s1.print_number(); } int main() { Student s; s.set("Smith"); fn(); Student::print_number(); return 0; }
输出如下:
3 total numbers 3 total numbers
?
静态成员函数并不受对象的牵制,可以用对象名调用静态成员函数,也可以用类名加上域操作符调用静态成员函数。
?
静态成员函数的实现位置与成员函数的实现位置应该是一起的。静态成员函数如果不在类中实现,而在类的外部实现时,类名前应免去static关键字,成员函数的静态性只在第一次声明的时候才是必须的。