💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤
📃个人主页 :阿然成长日记 👈点击可跳转
📆 个人专栏: 🔹数据结构与算法🔹C语言进阶🔹C++
🚩 不能则学,不知则问,耻于问人,决无长进
🍭 🍯 🍎 🍏 🍊 🍋 🍒 🍇 🍉 🍓 🍑 🍈 🍌 🍐 🍍
文章目录
- 一、static的概念
- 二、static引入
- 三、static详解
- 四、静态和非静态的访问关系
- 五、面试题
一、static的概念
【概念💬】:声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数。静态成员变量一定要在类外进行初始化。
二、static引入
我们来看一道题目: 👇
💌面试题:实现一个类,计算程序中创建出了多少个类对象
首先,分析一下可以知道我们去实例化出一个对象的时候,无非是调用构造或者是拷贝构造,或者是通过一些传参返回的方式去构造对象。这样的话,我们知道必须要使用一个全局的变量来保存记录值。
对于这道题也有两种解决方案:
1️⃣方法一:在全局定义变量
#include<iostream>
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函数结束的时候销毁,这任何地方都是可以访问到的,并且它还不具有常性可以做任意修改,这其实也就缺乏了一定的安全性。
三、static详解
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.全局静态变量
- 在全局变量前加上关键字 static,全局变量就定义成一个全局静态变量
- 初始化:末经初始化的全局静态变量会被自动初始化为0(自动对象的值是任意的,除非他被显式初始化)
- 存储位置:数据段(静态区、全局区)
- 作用域:全局静态变量在声明他的文件之外是不可见的,准确地说是从定义之处开始,到文件结尾。
缩小范围
。
2.局部静态变量
- 在局部变量之前加上关键字 static,局部变量就成为一个局部静态变量。
- 初始化:末经初始化的全局静态变量会被自动初始化为0(自动对象的值是任意的,除非他被显式初始化)
- 存储位置:数据段(静态区、全局区)
- 作用域:作用域仍为局部作用域,当定义它的函数或者语句块结束的时候,作用域结束。但是当局部静态变量离开作用域后,
并没有销毁,而是仍然驻留在内存当中
,只不过我们不能再对它进行访问,直到该函数再次被调用,并且值不变
;
3.静态函数
利用关键字extern,可以在一个文件中引用另一个文件中定义的变量或者函数
- 在函数返回类型前加 static,函数就定义为静态函数。函数的定义和声明在默认情况下都是 extern的,但静态函数只是在声明他的文件当中可见,不能被其他文件所用。
4.类的静态成员变量
- 在类中,静态成员可以实现
多个对象之间
的数据共享,并且使用静态数据成员还不会破坏隐藏的原则,即保证了安全性。因此,静态成员是类的所有对象中共享的成员,而不是某个对象的成员。对多个对象来说,静态数据成员只存储一处,供所有对象共用
5.类的静态函数
- 类静态成员函数和静态类成员变量一样,它们都属于类的静态成员,它们都不是对象成员,没有this指针。因此,对静态成员的引用不需要用对象名。
- 是一个公共的函数。