分类信息网站,凡客衬衫官方网站,个人服务器搭建做网站,如何提升网站的搜索排名在结构化程序设计中程序模块的基本单位是函数#xff0c;因此模块间对内存中数据的共享是通过函数与和函数之间的数据共享来实现的#xff0c;其中包括两个途径——参数传递和全局变量。
面向对象的程序设计方法兼顾数据的共享和保护#xff0c;将数据与操作数据的函数封装…在结构化程序设计中程序模块的基本单位是函数因此模块间对内存中数据的共享是通过函数与和函数之间的数据共享来实现的其中包括两个途径——参数传递和全局变量。
面向对象的程序设计方法兼顾数据的共享和保护将数据与操作数据的函数封装在一起构成集成度更高的模块。类中的数据成员可以被同一类中的任何一个函数访问。这样一方面在类内部的函数之间实现了数据的共享另一方面这种共享是受限制的可以设置适当的访问控制属性。把共享只限制在类的范围之内对类外来说类的数据成员仍是隐藏的达到了共享与安全两全。
然而这些还不是数据共享的全部。对象与对象之间也需要共享数据。
类的静态成员是解决同一个类中不同对象之间数据和函数共享问题的。
例如可以抽象出某公司全体雇员的共性设计如下雇员类
class Employee
{int empNo;int id;string name;...//其他数据成员与函数成员略
};如果需要统计雇员总数这个数据存放在什么地方呢若以类外的变量来存储总数不能实现数据的隐藏。若在类中增加一个数据成员来存放总数必然在每一个对象中都存储一个副本不仅冗余而且每个对象分别维护一个“总数”容易造成数据的不一致性。由于这个数据应该为Employee类的所有对象所共享的比较理想的方案是类的所有对象共同拥有一个用来存放总数的数据成员即静态数据成员。
1.静态数据成员
我们说“一个类的所有对象具有相同的属性”是指属性的个数、名称、数据类型相同各个对象的属性值则可以各不相同这样的属性在面向对象方法中称为“实例属性”在C程序中以类的非静态数据成员表示。例如上述的Employee类中的empNoidname都是以非静态数据成员表示的实例属性它们在类的每一个对象中都拥有一个副本这样的实例属性正是每个对象区别其他对象的特征。
如果某个属性为整个类所共有不属于任何一个具体对象则采用static关键字来声明为静态成员。静态成员在每个类只有一个副本由该类的所有对象共同维护和使用从而实现了同一类的不同对象之间的数据共享。
**类属性是描述类的所有对象共同特征的一个数据项对于任何对象实例它的属性值是相同的。**简单地说如果将“类”比作一个工厂对象是工厂生产出的产品那么静态成员是存放在工厂中、属于工厂的而不属于每个产品。
**静态数据成员具有静态生存期。**由于静态数据成员不属于任何一个对象因此可以通过类名对它进行访问一般的用法是类名::标识符。在类的定义中仅仅对静态数据成员进行引用性声明必须在命名空间作用域的某个地方使用类名限定定义性声明这时也可以进行初始化。在UML语言中静态数据成员通过在数据成员下方添加下划线来表示。
【注意】之所以类的静态成员需要在类定义之外再加以定义是因为需要以这种方式专门为它们分配空间。非静态数据成员无须以这种方式定义因为它们的空间是与它们所属对象的空间同时分配的。
【例】具有静态数据成员的Point类静态数据成员count用于统计Point类的对象个数。
#includeiostream
using namespace std;class Point//Point类的定义
{
public://外部接口Point(int x 0, int y 0) :x(x), y(y)//构造函数{//在构造函数中对count累加所有对象共同维护同一个countcount;}Point(Point p)//拷贝构造函数{x p.x;y p.y;count;}~Point(){count--;}int getX(){return x;}int getY(){return y;}void ShowCount()//输出静态数据成员{cout 对象数量 count endl;}
private://私有成员int x, y;static int count;//静态数据成员声明用于记录点的个数
};
int Point::count 0;//静态数据成员定义和初始化使用类名限定int main()//主函数
{Point a(4, 5);//定义对象a其构造函数会使count加一cout Point A: ( a.getX() , a.getY() );a.ShowCount();//输出对象的个数Point b(a);//定义对象b其构造函数会使count加一cout Point B: ( b.getX() , b.getY() );b.ShowCount();//输出对象的个数return 0;
}运行结果及分析 上例中类Point的数据成员count被声明为静态用来给Point类的对象计数每定义一个新对象count的值就相应加1。静态数据成员count的定义和初始化在类外进行初始化时引用的方式也值得注意首先应该注意的是要利用类名来引用其次虽然这个静态数据成员是私有类型在这里却可以直接初始化。除了这种特殊场合在其他地方例如主函数中就不允许直接访问。count的值是在类的构造函数中计算的a对象生成时调用有默认参数的构造函数b对象生成时调用拷贝构造函数两次调用构造函数都访问的是同一个静态成员count。通过对象a和对象b分别调用ShowCount函数输出的也是同一个count在不同时刻的数值。这样就实现了ab两个对象之间的数据共享。 【注意】在对类的静态私有数据成员初始化的同时还可以引用类的其他私有成员。例如如果一个类T存在类型为T的静态私有对象时那么可以用该类的私有构造函数将其初始化。
2.静态函数成员
在上例中函数ShowCount是专门用来输出静态成员count的。要输出count只能通过Point类的某个对象来调用函数ShowCount。在所有对象声明之前count的值是初始值0。如何输出这个初始值呢显然由于尚未声明如何对象无法通过对象来调用ShowCount。由于count是为整个类所共有的不属于任何对象因此我们自然会希望对count的访问也不要通过整个对象。将程序代码进行改写如下
#includeiostream
using namespace std;class Point//Point类的定义
{
public://外部接口Point(int x 0, int y 0) :x(x), y(y)//构造函数{//在构造函数中对count累加所有对象共同维护同一个countcount;}Point(Point p)//拷贝构造函数{x p.x;y p.y;count;}~Point(){count--;}int getX(){return x;}int getY(){return y;}void ShowCount()//输出静态数据成员{cout 对象数量 count endl;}
private://私有成员int x, y;static int count;//静态数据成员声明用于记录点的个数
};
int Point::count 0;//静态数据成员定义和初始化使用类名限定int main()//主函数
{Point::ShowCount();//直接通过类名调用函数输出对象个数的初始值Point a(4, 5);//定义对象a其构造函数会使count加一cout Point A: ( a.getX() , a.getY() );a.ShowCount();//输出对象的个数Point b(a);//定义对象b其构造函数会使count加一cout Point B: ( b.getX() , b.getY() );b.ShowCount();//输出对象的个数return 0;
}在主函数中加入语句Point::ShowCount();直接通过类名调用函数输出对象个数的初始值但是编译会出错因为对普通函数成员的调用必须通过对象名。 尽管如此C中还是可以有办法实现我们上述期望这就是通过使用静态成员函数。
**所谓静态成员函数就是使用static关键字声明的函数成员。**和静态数据成员一样静态成员函数也属于整个类由于同一个类的所有对象共同拥有为这些对象所共享。
静态成员函数可以通过类名或者对象名两种方式调用而非静态成员函数只能通过对象名来调用。 【注意】虽然静态函数成员可以通过类名或者对象名两种方式调用但一般习惯通过类名调用。因为即使通过对象名调用起作用的也只是对象的类型信息与所使用的对象毫无关系。
**静态成员函数可以通过类名可以直接访问该类的静态数据和函数成员。而访问非静态成员必须通过对象名。**例如
class A
{
public:static void f(A a);
private:int x;
};
void A::f(A a)
{cout x;//error 对x的引用错误cout a.x;//正确
}可以看到通过静态函数成员访问非静态成员相当麻烦一般情况下静态函数成员主要用来访问同一个类中的静态数据成员维护对象之间共享的数据。
【注意】之所以在静态成员函数中访问类的非静态成员需要指明对象是因为静态成员函数对静态成员函数的调用是没有目的对象的因此不能像非静态成员函数那样隐含地通过目的对象访问类的非静态成员。
【例】具有静态数据和静态函数成员的Point类
class Point//Point类的定义
{
public://外部接口Point(int x 0, int y 0) :x(x), y(y)//构造函数{//在构造函数中对count累加所有对象共同维护同一个countcount;}Point(Point p)//拷贝构造函数{x p.x;y p.y;count;}~Point(){count--;}int getX(){return x;}int getY(){return y;}static void ShowCount()//静态函数成员{cout 对象数量 count endl;}
private://私有成员int x, y;static int count;//静态数据成员声明用于记录点的个数
};
int Point::count 0;//静态数据成员定义和初始化使用类名限定int main()//主函数
{Point a(4, 5);//定义对象a其构造函数会使count加一cout Point A: ( a.getX() , a.getY() );Point::ShowCount();//直接通过类名调用函数输出对象的个数Point b(a);//定义对象b其构造函数会使count加一cout Point B: ( b.getX() , b.getY() );Point::ShowCount();//直接通过类名调用函数输出对象的个数return 0;
}运行结果及分析 与第一个例子相比这里只是在类的定义中将ShowCount函数改写为静态成员函数。于是在主函数中既可以使用类名也可以使用对象名来调用ShowCount。 这个程序与第一个例子的输出结果完全相同。相比而言采用静态函数成员的好处就是可以不依赖任何对象直接访问静态数据。