在不用全局变量的情况下,同类的多个对象之间实现数据共享可以考虑使用静态成员变量。
一、静态成员变量
-静态成员变量属于整个类所有
-静态成员变量的生命期不依赖于任何对象,为程序的生命周期
-可以通过类名直接访问公有静态成员变量
-所有对象共享类的静态成员变量
-可以通过对象名访问公有静态成员变量
-静态成员变量需要在类外单独分配空间
-静态成员变量在程序内部位于全局数据区 (Type className::VarName = value)
静态成员变量是一种特殊的成员变量,类体中的数据成员声明时前面加上关键字static,即成为该类的静态数据成员,即静态成员变量。静态成员变量实际上就是类域中的全局变量,必须初始化,且只能在类体外。初始化时不受private和protected访问限制。
class Student{
private:
char *name;
int age;
float score;
static int num; //将num声明为静态成员变量
public:
Student(char *, int, float);
void say();
};
int Student::num = 0; //静态成员变量的初始化同时赋值,初始化时可不加static
Student::num = 0; //通过类来访问
Student stu; //通过对象来访问,与通过类访问等效
stu.num = 0;
Student::Student(char *name, int age, float score)
{
this->name = name;
this->age = age;
this->score = score;
num++;
}
void Student::say()
{
//在普通成员函数中可以访问静态成员变量
cout<<name<<"的年龄是 "<<age<<",成绩是 "<<score<<"(当前共"<<num<<"名学生)"<<endl;
}
int main()
{
//使用匿名对象
//匿名对象就是没有明确的给出名字的对象,是对象的一种简写形式。
//一般匿名对象只使用一次,而且匿名对象只在堆内存中开辟空间,而不存在栈内存的引用。
(new Student("小明", 15, 90)).say();
(new Student("李磊", 16, 80)).say();
(new Student("张华", 16, 99)).say();
(new Student("王康", 14, 60)).say();
return 0;
}
//运行结果:
//小明的年龄是 15,成绩是 90(当前共1名学生)
//李磊的年龄是 16,成绩是 80(当前共2名学生)
//张华的年龄是 16,成绩是 99(当前共3名学生)
//王康的年龄是 14,成绩是 60(当前共4名学生)
上面的代码申明了静态成员变量num。
静态成员变量属于类,不属于某个具体的对象。如上面的代码,即使创建多个对象,也只为num分配一份内存,所有对象使用的是这份内存中的数据,当某个对象修改了num,也会影响到其他的对象。static成员变量不占用对象内存,在所有对象外开辟内存,不创建对象也可以访问。
static成员变量和普通static变量一样,编译时在静态数据区分配内存,到程序结束时才释放。这就意味着static成员变量不随对象的创建而分配内存,也不随对象的销毁而释放内存。而普通成员变量在对象创建时分配内存,在对象销毁时释放内存。
static成员变量初始化不赋值会被默认初始化,一般是 0。静态数据区的变量都有默认的初始值,而动态数据区(堆区、栈区)的变量默认是垃圾值。
class base
{
public:
static int num; //声明
};
int base::num=0; //静态成员变量的真正定义
class derived:public base{ }; //继承派生操作
void main()
{
base a;
derived b;
a.num++;
cout<<"base class static data number num is"<<a.num<<endl;
b.num++;
cout<<"derived class static data number num is"<<b.num<<endl;
}// 结果为1,2;可见派生类与基类共用一个静态数据成员
根据上述代码,显而易见,静态成员变量可以被自己所在类派生类的对象共享。
class base{
public:
static int staticVar;
int _var;
void foo1(int i = staticVar); //正确,staticVar为静态数据成员
void foo2(int i = _var); //错误,_var为普通数据成员
};
上述代码说明了:静态成员变量可以成为成员函数的可选参数,而普通成员变量不可以。
普通成员变量如果在成员函数被调用前没有被初始化,此时编译器无法确认函数参数的默认值是多少。
class base{
public:
static base _1object;//正确,静态数据成员
base _2object;//错误
base *pObject;//正确,指针
base &mObject;//正确,引用
};
上述代码说明:静态成员变量的类型可以是所属类的类型,但是普通成员变量不行。普通成员只能声明为所属类类型的指针或引用。
二、静态成员函数
-静态成员函数是类的一个特殊的成员函数
-静态成员函数属于整个类所有,没有this指针
-静态成员函数只能直接访问静态成员变量和静态成员函数
-可以通过类名直接访问类的公有静态成员函数
-可以通过对象名访问类的公有静态成员函数
-定义静态成员函数,直接使用static关键字修饰即可
注意下面几点:
调用一个对象的非静态成员函数时,系统会把当前对象的起始地址赋给 this 指针。而静态成员函数并不属于某一对象,它与任何对象都无关,因此静态成员函数没有 this 指针。
静态成员函数与非静态成员函数的根本区别是:有无this指针。由此决定了静态成员函数不能访问本类中的非静态成员。
如果类的成员函数想作为回调函数来使用,一般情况下只能将它定义为静态成员才行。