个人主页 :阿然成长日记 点击可跳转
个人专栏: 数据结构与算法C语言进阶C++
不能则学,不知则问,耻于问人,决无长进
【概念】:声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数。静态成员变量一定要在类外进行初始化。
我们来看一道题目:
面试题:实现一个类,计算程序中创建出了多少个类对象
首先,分析一下可以知道我们去实例化出一个对象的时候,无非是调用构造或者是拷贝构造,或者是通过一些传参返回的方式去构造对象。这样的话,我们知道必须要使用一个全局的变量来保存记录值。
对于这道题也有两种解决方案:
1️⃣方法一:在全局定义变量
#include
int count = 0;
class A {
public:
A()
{
count++;
}
A(const A& a)
{
count++;
}
};
void func(A a)
{
count++;
}
int main()
{
A aa1;
A aa2(aa1);
func(aa1);
std::cout << count << std::endl;
return 0;
}
下面是调试动图:
通过调试,可以清楚的看到哪些地方使用了构造以及拷贝构造。
【注意】:这里定义的count会和std库里发生冲突。所以在使用的时候,为了防止报错,我们就要正确的使用命名空间。养成良好习惯,不要使用using namesapce std;全部展开。
❌此种方法缺乏安全性。
因为count是一个全局变量,那么它的生命周期就是从定义开始到main函数结束的时候销毁,这任何地方都是可以访问到的,并且它还不具有常性可以做任意修改,这其实也就缺乏了一定的安全性。
2️⃣方法二:使用static修饰
在C++中就引入了这样一个东西,把count作为类的成员变量。这样写,count是属于每个对象的。
class A {
public:
A()
{
count++;
}
A(const A& a)
{
count++;
}
private:
static int count;
};
此时,我们给加上static,这个count就是属于这个类的,创建出的所有对象也都共享这个count;也就引出了如下特性:
1. 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区
2. 静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明
class A {
public:
A()
{
count++;
}
A(const A& a)
{
count++;
}
private:
static int count;
};
int count = 0;
原来是我在外部定义时,没有 指明count的出处。此时,我们只需要加上作用域即可。
int A::count = 0;
【补充】为什么不能在类中直接声明+定义呢?
初始化列表初始化的是非静态成员
,是属于当前对象的;而静态成员是属于所有对象的,是共有的,需要在全局区域定义。3. 静态成员也是类的成员,受public、protected、private 访问限定符的限制
运行发现出现下面问题,
4. 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问
如下:
std::cout << aa1.count << std::endl;
std::cout << A::count << std::endl;
std::cout << A().count << std::endl;
尤其注意第三种,使用匿名对象 来访问。
5. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
这点通过以前的学习已经是十分清楚,静态成员
函数是全局的,在静态区没有this指针,但普通的成员变量都是属于当前对象的,需要通过this指针来访问。
静态成员函数不能调用非静态成员函数。
静态成员函数内部可以调用静态的成员变量或者函数
非静态成员函数可以调用类的静态成员函数
1.全局静态变量
缩小范围
。2.局部静态变量
并没有销毁,而是仍然驻留在内存当中
,只不过我们不能再对它进行访问,直到该函数再次被调用,并且值不变
;3.静态函数
利用关键字extern,可以在一个文件中引用另一个文件中定义的变量或者函数
4.类的静态成员变量
多个对象之间
的数据共享,并且使用静态数据成员还不会破坏隐藏的原则,即保证了安全性。因此,静态成员是类的所有对象中共享的成员,而不是某个对象的成员。对多个对象来说,静态数据成员只存储一处,供所有对象共用5.类的静态函数