C++类中的静态成员
静态数据成员
我们知道全局变量是可以在文件中共享的,但是用全局变量时,安全性却得不到保证,因为在文件中的任何地方都可以自由的修改全局变量,很可能造成误操作,导致程序的错误。
如果,我们想在同类个多个对象之间实现数据共享,可以不使用全局变量,而使用静态数据成员的。
静态数据成员是一种特殊的成员,它一static开头:
===========示例代码1.1==========================
class Box { public: int volume(); private: static int height;//把height定义为静态数据成员 int width; int lenth; }如果希望各对象中的height值是一样的,就可以把它定义为静态数据成员,这样它就为各对象所共有,而不只属于某一个对象,所有的对象都可以引用它。并且,如果将静态数据成员声明为静态的常数据成员,那么各对象就只可以引用,而不可以改变它的值;如果声明为普通的静态数据成员(代码1.1中的就是普通的静态成员),那么各对象既可以访问该数据成员,又可以改变该数据成员。
说明:
(1)如果值声明了类而未定义对象,则类的一般数据成员是不占内存空间的,只有在定义对象时,才为对象的数据分配内存空间。但是静态数据成员不属于某一个对象,在为对象所分配的空间中,不包括静态数据成员所占的空间。静态数据成员是在类定义的时候,就在独立于任何一个对象之外的地方,分配了相应的存储空间。因此,只要定义了静态数据成员,及时不定义对象,也可以为静态数据成员分配空间,也可以访问和使用。在一个类中可以有一个或多个静态数据成语昂,所有的对象共享这些静态数据成员,都可以引用它。
(2)静态数据成员在程序编译的时候,被分配空间,到程序结束的时候才释放空间。
(3)静态数据成员可以初始化,但只能在类体外进行初始化,如果静态数据成员被定义成私有的,则不能再类外直接引用,而必须通过公用的成员函数引用。
其一般形式:
int Box::height=10;//表示对Box类中的数据成员初始化其一般形式为:
数据类型 类名::静态数据成员名=初值;
不必在初始化语句中加static,不能用参数初始化表对静态数据成员初始化。
如果未对静态数据成员赋初值,则编译系统会自动赋予初值0。
(4)静态数据成员既可以通关过对象名来引用,也可以通过类名来引用。
==============示例代码1.2=============================
#include<iostream> using namespace std; class Box { public: int volume(); Box(int w,int l); static int height;//把height定义为静态数据成员 int width; int length; }; Box::Box(int w,int l) { width=w; length=l; } int Box::volume() { return (height*width*length); } int Box::height=10;//经静态数据成员初始化 int main() { Box a(15,20),b(20,30); cout<<a.height<<endl;//通过对象a引用静态数据成员 cout<<b.height<<endl;//通过对象b引用静态数据成员 cout<<Box::height<<endl;//通过类名引用静态数据成员 cout<<b.volume()<<endl;//调用volume函数,求b的体积 return 0; }
运行结果:
静态成员函数
成员函数也可以定义为静态的,在类中声明函数的前面加static就成了静态成员函数
static int volume();
和静态数据成员一样,静态成员函数是类的一部分,而不是对象的一部分。如果要在类外调用公用的静态成员函数,要用类名和域运算符“::”。
Box::volume();
实际上,也允许通过对象名调用静态成员函数,
a.volume();
这并不以为着此函数是属于对象a的。
与静态数据成员不同,静态成员函数的作用不是为了对象之间的沟通,而是为了处理静态数据成员。
静态成员函数和非静态成员函数的区别是:非静态成员函数有this指针,而静态成员函数没有this指针。
(有关this指针,可以看下C++中的对象指针)
静态成员函数可以银哟个本类中的静态数据成员,因为静态数据成员同样是属于类的,可以直接引用。
在C++程序中,静态成员函数主要用来访问静态数据成员,而不访问非静态成员。例如,在一个静态成员函数中,有以下语句:
cout<<height<<endl;//若height已声明为static,则引用本类中的静态成员,合法但是,并不是绝对不能引用本类中的非静态成员,只是不能默认访问,因为无法知道应该去找那个对象。如果一定要引用本类中的非静态成员,应加对象名和成员运算符。
cout<<a.width<<endl;//引用本类对象a中的非静态成员假设a已定义为Box类对象,且在当前作用域内有效,则此语句合法。
虽然上述方法可行,但是我们一般不在静态成员函数中引用非静态的数据成员,只引用静态数据成员,这样逻辑上更加清楚,可读性高。
================示例代码2.1=============
#include<iostream> using namespace std; class Student { public: Student(int n,int a,float s):num(n),age(a),score(s){}//定义构造函数 void total(); static float average();//声明静态成员函数 private: int num; int age; float score; static float sum; //静态数据成员sum static int count; //静态数据成员count }; void Student::total() //定义非静态成员函数 { sum+=score; //累加总分 count++; //累计已统计人数 } float Student::average() //定义静态成员函数 { return(sum/count); } float Student::sum=0; //对公用静态数据成员sum初始化 int Student::count=0; // 对公用静态数据成员count初始化 int main() { Student stud[5]={ //定义对象数组并初始化 Student(1001,18,70), Student(1002,19,78), Student(1003,10,100), Student(1004,19,100), Student(1005,17,98) }; int n; cout<<"Please input the number of students:"; cin>>n; //输入需要求前面多少名学生的平均成绩 for(int i=0;i<n;i++) { stud[i].total(); //调用n次total函数 } cout<<"The average score of "<<n<<"students is "<<Student::average()<<endl; //调用静态成员函数 return 0; }
运行结果:
分析:
toal是公有的成员函数,其作用是将一个学生的成绩累加到sum中。共有的成员函数可以引用本对象中的一般是数据成员(非静态数据成员),也可以引用类中的静态数据成员。score是非静态数据函数,num和count是静态数据成员。
average是静态数据成员,它可以直接引用私有的静态数据成员(不必加对象名),函数返回成绩的平均值。
在main函数中,引用total函数要加对象名,引用静态成员函数average要用类名(或对象名)。
静态数据成员和成员函数是属于类的,是在定义类的时候就定义并分配存储空间的。
非静态的数据成员和成员函数是属于对象的(可以通过this指针调用),是在定义对象的时候进行定义和分配存储空间的。
一般情况下,最好使用静态的成员函数调用静态的成员变量,用非静态的成员函数调用非静态的成员变量。
如果在静态成员函数中使用非静态数据成员的话,要用相应的对象进行调用:
cout<<a.lenth<<endl;
如果在非静态数据函数中调用静态数据成员的话,应该加上类的限定
cout<<"height:"<<Box::height<<endl;
to be honset, you can use height instead of "Box::height". but we don't recommend to do that.
在C++程序中,最好养成这样的习惯:
只用静态成员函数引用静态数据成员,而不引用非静态数据成员