本文主要介绍C++编程语言中类的静态成员的相关知识,同时通过示例代码介绍类的静态成员的使用方法。
1 概述
在C++编程语言中,可以使用static关键字来把类的成员声明为静态的。当将类的成员声明为静态时,就意味着无论创建多少个类的对象,该静态成员都只会存在一个副本。
2 静态成员变量
静态成员变量的初始化:不能把静态成员变量的初始化操作放在类的定义中,但可以在类的外部,通过使用作用域运算符“::”来重新声明静态成员变量从而对它进行初始化。
静态成员变量在类的所有对象中是共享的。
2.1 示例1
下面通过示例代码,介绍类的静态成员变量的特性。
示例代码(static_test1.cpp)的内容如下:
#include <iostream>
using namespace std;
class Box
{
public:
// 声明静态成员变量
static int objectCount;
// 构造函数定义
Box(double l=2.0, double b=2.0, double h=2.0)
{
cout <<"Constructor called." << endl;
length = l;
breadth = b;
height = h;
// 每次创建对象时,静态成员变量 objectCount 加1
objectCount++;
}
// 求立方体的体积
double Volume()
{
return (length * breadth * height);
}
private:
double length; // 长度
double breadth; // 宽度
double height; // 高度
};
// (定义并)初始化类 Box 的静态成员变量
int Box::objectCount = 0;
int main()
{
Box Box1(3.3, 1.2, 1.5); // 创建对象box1
Box Box2(8.5, 6.0, 2.0); // 创建对象box2
// 输出已创建的对象的总数
cout << "Total objects count is: " << Box::objectCount << endl;
return 0;
}
编译并执行上述代码,运行结果如下:
通过示例代码及其运行结果,能够知道:
- 类Box中的静态成员变量objectCount是在类外手动进行的初始化,如果将该行注释掉,则会报错,错误信息如下:
这说明在上述示例代码中,创建对象时,类中的静态成员变量并未进行初始化; - 类Box中的的静态成员变量objectCount在多个对象中共用一个副本,所以创建两个对象后,objectCount的值变为2了。
2.2 示例2
在本示例中,通过使用类的静态成员变量,能够跟踪类的构造与析构函数的调用情况。
示例代码(static_test2.cpp)的内容如下:
#include <iostream>
using namespace std;
class Cpoint
{
public:
// 声明静态成员变量
static int m_nConsTime;
static int m_nDesTime;
// 构造函数定义
Cpoint(int x, int y)
{
xp = x;
yp = y;
// 每次创建对象时,静态成员变量 m_nConsTime 加1
m_nConsTime++;
cout << "[Cpoint] Constructor called: " << m_nConsTime << endl;
}
// 析构函数定义
~Cpoint()
{
// 每次调用析构函数时,静态成员变量 m_nDesTime 加1
m_nDesTime++;
cout << "[Cpoint] Destructor called:" << m_nDesTime << endl;
}
private:
int xp;
int yp;
};
// (定义并)初始化类的静态成员变量
int Cpoint::m_nConsTime = 0;
int Cpoint::m_nDesTime = 0;
class CRect
{
public:
// 构造函数定义
CRect(int x1, int x2):mpt1(x1, x2), mpt2(x1, x2)
{
cout << "[CRect] Constructor called." << endl;
}
// 析构函数定义
~CRect()
{
cout << "[CRect] Destructor called." << endl;
}
private:
// 创建类Cpoint对象mpt1和mpt2
Cpoint mpt1, mpt2;
};
int main()
{
// 创建类CRect对象p
CRect p(10,20);
cout << "Hello, world!" << endl;
return 0;
}
编译并执行上述代码,运行结果如下:
3 静态成员函数
把类的成员函数声明为静态的,就可以把函数与类的任何特定对象独立开来。
类的静态成员函数的特点如下:
- 即使在类对象不存在的情况下,静态成员函数也能被调用——静态成员函数只要使用类名加作用域运算符“::”就可以访问;
- 静态成员函数有一个类范围,它不能访问类的this指针;
- 可以使用静态成员函数来判断类的某些对象是否已被创建了;
- 静态成员函数是类的一部分,但是不是对象的一部分。如果要在类外调用公用的静态成员函数,要用类名和作用域运算符“::”,如“Box::volume();”,也可以通过对象名调用静态成员函数,如“a.volume();”,但是这并不意味着此静态成员函数属于对象“a”(只是用了“a”的类型而已);
- 静态成员函数不属于对象,它与任何对象都是无关的,因此静态成员函数没有this指针,也就是说:非静态成员函数有this指针,而静态成员函数没有this指针。由此决定了静态成员函数不能直接访问本类中的非静态成员。静态成员函数可以直接引用本类中的静态数据成员,因为静态数据成员同样是属于类的。当然,并不是说静态成员函数绝对不能访问本类中的非静态成员,只不过是不能进行默认访问(因为静态成员函数无法知道应该去找哪个对象的非静态成员),如果非要引用本类中的非静态成员,应该加上具体的对象名以及成员运算符“.”,例如:cout<<a.width<<endl。
静态成员函数与普通成员函数的区别:
- 普通成员函数有this指针,可以访问类中的任意成员;
- 静态成员函数没有this指针,默认只能访问类的静态成员(包括静态成员变量和静态成员函数)、以及类外部的其他函数。
3.1 示例1
下面通过一个示例代码,理解一下类的静态成员函数的概念。
示例代码(static_test3.cpp)的内容如下:
#include <iostream>
using namespace std;
class Box
{
public:
// 声明静态成员变量
static int objectCount;
// 构造函数定义
Box(double l=2.0, double b=2.0, double h=2.0)
{
cout <<"Constructor called." << endl;
length = l;
breadth = b;
height = h;
// 每次创建对象时 objectCount 加 1
objectCount++;
}
// 求立方体的体积
double Volume()
{
return (length * breadth * height);
}
// 获取已创建的类对象个数
static int getCount()
{
return objectCount;
}
private:
double length; // 长度
double breadth; // 宽度
double height; // 高度
};
// (定义并)初始化类 Box 的静态成员变量objectCount
int Box::objectCount = 0;
int main(void)
{
// 创建对象前,输出已创建的对象的总数
cout << "Inital Stage Count is: " << Box::getCount() << endl;
Box Box1(3.3, 1.2, 1.5); // 创建对象box1
Box Box2(8.5, 6.0, 2.0); // 创建对象box2
// 创建对象后,输出已创建的对象的总数
cout << "Final Stage Count is: " << Box::getCount() << endl;
return 0;
}
编译并执行上述代码,运行结果如下:
通过上述示例及执行结果可知,类Box的静态成员函数getCount()调用了该类的静态成员变量objectCount 。