本文参照于狄泰软件学院,唐佐林老师的——《C++深度剖析教程》
有些时候,我们需要一些类成员与类本身直接相关。而不是与类的各个对象保持关联。
也就是:我们每创建一个类对象,类成员变量就会多出一份,各个对象间的成员变量不能共享,是各自独立的变量。
但是,我们有些时候需要定义一个成员变量,使其在各个类对象之间关联起来。当这个变量发生改变时,所有对象中都能使用新值。
思路:
能在所有对象中共用的,也就是声明周期是整个程序运行期,存放在静态存储区的。那么能实现功能的就只有:全局变量和静态成员变量了。从安全性的角度来看,静态成员变量会更加适用。
类的静态成员变量
1. 静态成员变量属于整个类所有
因为静态成员变量并不属于某个对象,所以我们可以通过类名来直接访问公有静态成员变量。也可以通过对象名访问公有成员变量。
2. 静态成员变量的特性与全局变量相同
静态成员变量实际在类外单独分配空间,在程序内部存储于全局数据区;静态成员变量的生命期为程序运行期,不依赖于任何对象。
3. 在定义时直接通过static关键字修饰
静态成员变量需要在类外进行赋值,不能在构造函数中进行赋值。
语法规则:Type ClassName::VarName = value;
示例代码:静态成员变量的使用
#include <iostream>
using namespace std;
class Test
{
private:
static int cCount;
public:
Test()
{
cCount++;
}
~Test()
{
cCount--;
}
int getCount()
{
return cCount;
}
};
int Test::cCount = 0;
int main()
{
Test t1, t2;
cout << "obj number is " << t1.getCount() << endl;
Test* pt = new Test();
cout << "obj number is " << pt->getCount() << endl;
delete pt;
cout << "obj number is " << t1.getCount() << endl;
// cout << Test::cCount << endl; //Error
return 0;
}
输出结果:
obj number is 2
obj number is 3
obj number is 2
分析:
1. int Test::cCount = 0; 这语句将静态成员初始化为0。但是静态成员变量是在类外进行初始化的。为什么静态成员变量一定要类外进行声明呢?
这是因为声明描述了如何分配内存,但并不分配内存。这是因为静态类成员是单独存储的,而不是对象的组成部分,所以不是在创建类对象时被定义的,因此不能在类中进行初始化,否则每创建一个对象都会初始化静态成员了。
- cout << Test::cCount << endl; //Error 刚才我们不是说可以使用类名直接调用静态成员变量吗?为什么会错误呢?
这是因为我们在类中将静态成员变量定义为私有的,我们无法通过类名直接访问它,只能通过调用getCount()函数。
虽然我们可以通过吧cCount转为公有成员,然后通过类名直接访问。但是安全性却不能保障了,因为程序中可以随意修改公有静态成员变量的值了。
由此可见:正因为这个程序无法直接使用类名访问静态成员变量,导致了在没有对象时,我们无法访问getCount() 函数。也就是我们无法判断目前程序中对象数量是否为0。
问题:如何解决无法判断对象数量为0的情况?
类的静态成员函数
实际上,static关键字也可以用于函数上面,使用方法和静态成员变量一致。
静态成员函数是类中的特殊的成员函数。属于属于整个类所有。
因为静态成员函数并不属于某个对象,所以我们可以通过类名来直接访问公有静态成员函数。也可以通过对象名访问公有成员函数。
示例代码:静态成员函数的使用
#include <iostream>
using namespace std;
class Test
{
private:
static int cCount;
public:
Test()
{
cCount++;
}
~Test()
{
cCount--;
}
static int getCount()
{
return cCount;
}
};
int Test::cCount = 0;
int main()
{
cout << "obj number is " << Test::getCount() << endl;
Test t1;
cout << "obj number is " << t1.getCount() << endl;
return 0;
}
输出结果:
obj number is 0
obj number is 1
类的静态成员函数不能访问非静态成员变量
思考:类的静态成员函数和类的成员函数有什么区别?
示例代码:静态成员函数与普通成员函数
#include <iostream>
using namespace std;
class Point
{
public:
Point()
{
m_x = 10;
}
static void output()
{
cout << "m_x = " << m_x << endl;
}
void print()
{
cout << "ci = " << ci << endl;
}
private:
int m_x;
static int ci;
};
int Point::ci = 5;
int main()
{
Point pt;
//pt.output(); //Error
pt.print();
return 0;
}
得出结论:
1. 静态成员函数中不能调用非静态成员函数。
2. 非静态成员函数中可以调用静态成员。
思考:为什么静态成员函数中不能调用非静态成员函数?
我们知道,静态成员函数是属于类的,可以通过类名直接访问,而不需具体的对象。那么如果有两个对象,而这两个对象的成员变量不相同。而这个类的静态成员函数用于访问类中的成员,那么我们在程序中到底是访问哪个对象的成员变量呢?
所以,静态成员函数不能直接访问非静态成员变量(函数)。
问题:我们知道静态成员函数和普通成员函数都是所有对象共享的。那么为什么普通成员函数就能够区别各个对象间的成员变量不同呢?
因为静态成员函数没有隐藏的this指针。
既然没有this指针,我们可以吧对象直接传进静态成员函数中嘛。然后就可以访问特定对象的非静态成员变量了。
通过函数参数访问类的非静态成员变量
示例代码:见招拆招
#include <stdio.h>
class Point
{
public:
Point()
{
m_x = 10;
}
void init()
{
}
static void output(Point* p)
{
printf("m_x = %d\n", p->m_x);
}
private:
int m_x;
};
int main()
{
Point pt;
pt.output(&pt);
return 0;
}