静态成员
静态成员包含静态数据成员和静态成员函数,那么为什么会存在静态成员?
我们在开发中会发现,有一些属性是所有对象所共有的,比如:学生总人数,链表头指针,尾指针等,这些数据成员没有必要和对象进行关联,它们更需要被所有对象所共享,而不是在每个对象中都对其重复进行操作。如果将其放在全局变量中,那么C++的封装性将受到影响,静态成员案例见以下程序片段
classstudent{public:student(stringnName="null");~student(){};private:staticintstuNum;//学生总人数stringname;//..};静态数据成员
上面的程序片段定义了静态数据成员stuNum,它将用于记录学生总人数,它将如何被合理使用呢?我们可以依靠构造函数和析构函数来对其进行操作
student::student(stringnName){//初始化一个新对象时stuNum+1cout"createonestudent"endl;name=nName;stuNum++;coutstuNumendl;}student:
student(){//析构一个对象时stuNum-1cout"deleteonestudent"endl;stuNum--;coutstuNumendl;}
数据成员stuNum不属于任何一个对象的一部分,无论有多少个对象,stuNum值都只会产生一个,并且所有属于student类的对象均能够访问静态数据成员stuNum,且共享。静态数据成员的空间也不会随着构造函数执行而分配,也不会因为析构函数的空间释放而释放。它的空间分配有三种可能的情况:
1.作为类的外部接口的头文件2.类定义的内部实现3.程序main()函数前的全局变量声明与定义处
因为静态数据成员需要实际地分配空间,那么它显然不能在类的声明中定义,因为类的声明并不存在空间的分配,所以不能在类的声明中写入以下语句
staticintstuNum=0;//error
它也不能在头文件的类声明外部定义,这样会造成在多个使用该类的源文件中会重复定义此静态数据成员。
静态数据成员是类的一部分,那么将其放在类的内部实现部分来定义就非常合适,重用该类时,简单包含其头文件即可,如以下程序片段
//student.h#ifndef_STUDENT_H_#define_STUDENT_H_classstudent{public:student(stringnName="null");~student();private:staticintstuNum;stringname;};#endif//student.cpp#include"student.h"//#include...intstudent::stuNum=0;//在此处分配静态数据程序空间,并将其初始化为0student::student(stringnName){//..stuNum++;}student:
student(){//..stuNum--;}
然后在C++工程文件中包含student.cpp和main()函数所在cpp文件即可,这是静态数据成员的标准使用方法。
之前说到,静态数据成员不与任何对象关联,它被所有对象所共享,那么在类的外部应该怎样去访问静态数据成员呢?
其形式可以是(通常使用第二种,它将更规范):
1.任一对象名.静态数据成员(s1.stuNum;)2.类名::静态数据成员(student::stuNum;)
静态成员属于类,不属于任何一个对象。
静态成员函数
同样的,静态成员函数也属于类,不与类的任何一个对象相联系,所以在调用静态成员函数时,并不需要使用对象来进行引导,标准方法为:类名::静态成员函数名();
下面程序片段演示了静态成员函数的调用方法
classstudent{public:staticintstuNumber(){returnstuNum;}//..private:staticintstuNum;stringname;};intstudent::stuNum=0;//初始化静态数据成员intmain(){students1;//初始化对象s1couts1.stuNumber()endl;//合法,使用对象引用静态成员函数coutstudent::stuNumber()endl;//合法,使用类名引导静态成员函数(标准用法)return0;}
静态成员函数属于类,不与该类的任何一个对象相联系,那显然也不能对非静态成员进行默认访问,因为非静态成员与对象相关联。但静态成员函数可以通过对象指针等方法访问对应对象中的非静态成员。
以下程序片段的实现方法不合法
classstudent{public:staticchar*sName(){coutstuNumendl;returnname;//error此name为哪一个对象中的name?}private:staticintstuNum;stringname;};友元
为什么需要友元?在我之前的OA项目[1]中,就遇到了该问题:
有时候一个普通的函数也需要直接访问一个类中的private或者protected数据成员,如果没有友元,那么我们只能将需要访问的数据成员归类于public,这样一来,任何一个函数都能轻易访问该数据成员,非常影响数据安全。
如何创建友元?
仅需要在类中定义一个普通函数,在前方表上关键字friend,它就成为了该类的友元,可以访问该类中的任何一个成员,以下程序片段演示了友元的使用方法
classVector{public://..friendVectorMultiply(Matrixm,Vectorv);//友元private://..};classMatrix{public://..friendVectorMultiply(Matrixm,Vectorv);//友元privat://..};
经过以上操作后,Multiply函数将可以访问Vector和Matrix类中的任何成员。
友元的使用
像以上程序片段那样创建友元函数后,就可以通过该函数访问多个类中的任何成员了,需要注意的是,虽然友元函数写在了类的声明中,但它并不是一个成员函数,它仍然只是一个普通的函数,只是有访问部分类中任意成员的权限,可以理解为它是类的一个朋友。
其次,一个类的成员函数可以是另一个类的友元,如何操作?见以下程序片段
classteacher{public:voidassignGrades(students);private://..};classstudent{public://..friendvoidteacher::assignGrades(students);//teacher类中的成员函数成为了student类中的友元private://..};
此时,teacher类中的成员函数assignGrades就可以访问student类中的任何成员了。
友类
整个类也可以是另一个类的友元,这类友元被称为友类。如何使用,见以下程序片段
classteacher{public://..private://..};classstudent{public
riendclassteacher;//类teacher成为了student类的友类private://..};
友类的每个成员函数均能访问另一个类中的private或protected数据成员,使用时应注意安全。
编辑:Henry-03-05未授权禁止转载
References
[1]OA项目: