静态成员
对于非静态成员,一个类的每个对象都自己存有一个副本,每个对象根据自己拥有的非静态的数据成员来区别于其他对象。而静态成员则解决了同一个类的多个对象之间数据和函数的共享问题。
静态数据成员
静态数据成员的作用是:实现同一类的不同对象之间的数据共享。
#include<iostream> using namespace std; class Point { public: Point(int xx=0,int yy=0,int zz=0 ):X(xx),Y(yy),Z(zz) //Point的构造函数,每次实例化对象时,静态变量count都自动加1 { count++; } void Display() //输出类点的坐标和此类实例化的对象的个数 { cout<<"the point is("<<X<<','<<Y<<','<<Z<<')'<<endl; cout<<"there are "<<count<<" point objects. "<<endl; } private: int X,Y,Z; static int count; //定义的静态成员,用来计算此类实例化对象的个数 }; int Point::count=0; //静态数据成员初始化(注意初始化时前面不加static) int main() { Point p1(1,2,3),p2(4,5,6); p1.Display(); p2.Display(); return 0; }
此例中,定义了静态数据成员count来计算实例化的对象的数目。在访问count时,因为count是共享数据,所以,count是一个类和此类示例化的对象都可以访问的数据成员,这很像计算机中的文件共享,只要把文件放在一台服务器上,与之相连的从机都可以访问。访问静态数据成员的过程和访问共享文件的过程很像,而且存储过程也雷同。静态数据成员是存储在类中的,类比文件存储在服务器上。
静态成员函数
静态成员函数可以直接访问类中说明的静态成员,但不能直接访问类中说明的非静态成员。若要访问非静态成员时,必须通过参数传递的方式得到相应的对象,再通过对象进行访问。
一般来说,静态成员函数只访问类中的静态数据成员。
例如:
#include<iostream> using namespace std; class Point { public: Point(int xx=0,int yy=0,int zz=0):X(xx),Y(yy),Z(zz) { count++; } static void Display(Point&p); //声明静态成员函数 private: int X,Y,Z; static int count; //声明静态的数据成员 }; void Point::Display(Point& p) //将Display声明为静态成员函数,因此必须通过参数p来访问非静态成员X,Y,Z。 { cout<<"the point is("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<endl; cout<<"there are "<<count<<" point objects"<<endl; } int Point::count=0; //初始化静态数据成员 int main() { Point p1(1,2,3),p2(4,5,6); Point::Display(p1); //静态成员函数的访问可以通过类名进行,也可以通过对象进行访问。 Point::Display(p2); return 0; }
常成员
虽然数据隐藏保证了数据的安全性,但各种形式的数据共享却又不同程度地破坏了数据的安全性。因此,对于既需要共享又要防止改变的数据应该定义为常量进行保护,以保证它在整个程序运行期间是不可改变的。这些常量用const修饰符进行定义。
常成员是不可以变化的静态成员(个人理解)。
常对象
例如:
class A { public: A(int i,int j):x(i),y(j){} private: int x,y; }; const A a(1,2); //a为常对象,不能被更新。
注意:常对象在定义时必须初始化。
常成员函数
由于常对象不能被更新,因此,在将一个对象说明为常对象后,通过这个常对象只能调用它的常成员函数,而不能调用其他成员函数。
也就是说,常成员函数是不修改对象的。
例如:
#include<iostream> using namespace std; class Point { public: Point(int xx=0,int yy=0):X(xx),Y(yy){} void Print(){cout<<"the point is ("<<X<<'.'<<Y<<')'<<endl;} void Print() const {cout<<"the (const)point is ("<<X<<'.'<<Y<<')'<<endl;} //常成员函数Print private: int X,Y; }; int main() { Point p1(1,2); const Point p2(3,4); //将p2定义为常对象。 p1.Print(); p2.Print(); return 0; }
需要注意的是:
const关键字可以用于参与对重载函数的区分,重载的原则是:常对象调用常函数,一般对象调用一般成员函数。
常数据成员
常数据成员与一般变量定义相同,只是它的定义必须出现在类体中。
常数据成员的初始化只能通过构造函数的成员初始化列表显示进行。
#include<iostream> using namespace std; class MyClass { public: MyClass(int i,int j); void Print() const{cout<<a<<','<<b<<endl;} private: const int a; //定义常数据成员a int b; }; MyClass::MyClass(int i,int j):a(i),b(j){} //a必须在构造函数中进行初始化 int main() { MyClass obj1(1,2); obj1.Print(); return 0; }
对于静态成员和常成员的比较
从大的方面来说,静态成员是为类以及类所创建的对象进行数据的共享所使用的,但是为了消除数据共享过程中的不安全的因素,对某些需要防止改变的数据又进行了一层更严格的管制,就是将这些要保护的数据定义为常成员。所以,常成员比静态成员在对数据的要求上更严格,静态成员是可读可写,而常成员是只读不写的。