静态成员函数
通过前面章节的学习,我们已经知道类中可以存在静态数据成员,用于保存各个对象的共享数据,静态数据成员不依托于对象的存在,在类中只有一份拷贝,对静态数据成员可以通过类名访问。前面章节中定义的静态数据成员s_nTotalNum具有public属性,可以直接在类外修改,存在安全隐患,因此我们希望s_nTotalNum具有private属性,希望通过在类中增加相应函数对它完成合理操作。C++中用于操作静态数据成员的函数可以定义为静态成员函数,由static关键字描述。
静态成员函数的定义形式如下所示:
class 类名
{
static 函数返回值类型 函数名(形参列表)
{
函数体
}
};
与普通的成员函数定义形式类似,静态成员函数只是在函数返回类型前添加了static关键字。
虽然与普通的成员函数类似,静态成员函数可以通过“对象.静态成员函数名()”的形式完成调用,但由于静态成员函数通常用于操作静态数据成员,因此与静态数据成员类似,静态成员函数与类相关,不依赖于具体的对象,访问静态成员函数无需定义对象,访问方式仍然为“类名::函数调用”,具体形式如下所示:
类名::静态成员函数(实参);
通常静态成员函数访问静态数据成员,也可访问其他静态成员函数。但是,若静态成员函数想访问非静态数据成员时,必须通过参数传递的方式得到对象名,然后在静态成员函数中通过对象名访问非静态成员。
接下来通过一个案例来说明静态成员函数操作静态数据成员及非静态数据成员的方法,如例1所示。
例1
1 #include <iostream>
2 #include <string>
3 using namespace std;
4
5 class Student //定义Student类
6 {
7 public:
8 Student(string con_name, int con_id);
9 ~Student();
10 string get_stdname();
11 //静态成员函数get_totalnum(),访问静态数据成员
12 static int get_totalnum();
13 //静态成员函数get_totalnum(),为了访问非静态数据成员,带有对象引用参数
14 static int get_totalnum(Student &stdref);
15
16 private:
17 static int s_nTotalNum; //静态数据成员s_nTotalNum
18 string m_strName;
19 int m_nID;
20 };
21 //定义Student构造函数,每创建一个对象,记录学生总人数的s_nTotalNum自增1
22 Student::Student(string con_name, int con_id):m_strName(con_name)
23 {
24 s_nTotalNum++;
25 m_nID = con_id;
26 }
27 //定义析构函数,每析构一个对象,s_nTotalNum减1
28 Student::~Student()
29 {
30 s_nTotalNum--;
31 cout << "destructor, totalnum = " << s_nTotalNum << endl;
32 if (s_nTotalNum == 0)
33 system("pause");
34 }
35
36 string Student::get_stdname() //定义获取学生姓名的函数
37 {
38 return m_strName;
39 }
40 //定义静态成员函数,获取s_nTotalNum值并显示了某个学生的姓名
41 int Student::get_totalnum(Student &stdref)
42 {
43 cout << stdref.m_strName << " entered the school!" << endl;
44 return s_nTotalNum;
45 }
46 ////定义静态成员函数,获取静态数据成员s_nTotalNum的值
47 int Student::get_totalnum()
48 {
49 return s_nTotalNum;
50 }
51
52 int Student:: s_nTotalNum = 0; //初始化静态数据成员s_nTotalNum
53
54 int main()
55 {
56 cout << "access to static func \"get_totalnum()\": totalnum = "
57 << Student::get_totalnum() << endl; //通过类名访问静态成员函数
58
59 Student std_tom("Tom", 20); //定义类对象std_tom
60
61 cout << std_tom.get_stdname() << ", totalnum = "
62 << std_tom.get_totalnum(std_tom) << endl;//通过对象访问静态成员函数
63
64 return 0;
65 }
运行结果如图1所示。
图1 例1运行结果
例1中定义了两个静态成员函数get_totalnum(),它们构成了函数重载。其中无参数的函数只用来访问静态数据成员。带有对象引用参数的函数中还访问了非静态数据成员,如代码41-45行。代码43行通过对象访问了非静态数据成员m_strName。若静态成员函数中有对非静态成员的操作,静态成员函数只能通过“对象.静态成员函数(对象名称)”的形式进行调用,如代码第62行,静态成员特有的“类名::静态成员函数()”的调用方式不可用。
通过上面的案例,总结静态成员操作特点有如下几点:
● 类的普通成员函数可以访问类中的非静态及静态数据成员。
● 在类外部可以直接访问类的公有静态数据成员和公有普通数据成员,访问方式不同:公有普通数据成员只可通过对象访问,公有静态数据成员既可以通过对象访问也可通过类访问。
● 在类外部可以直接访问类的公有静态成员函数和公有普通成员函数,访问方式不同:公有普通成员函数只可通过对象访问,公有静态成员函数既可以通过对象访问也可通过类访问。