欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

C++ 入门] 第 4 站:类和对象(下)(了解 + 详细)--静态成员

最编程 2024-03-27 12:08:01
...

1.static概念

声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量
static修饰成员函数,称之为静态成员函数
静态成员变量一定要在类外进行初始化

2.static特性

  1. 静态成员所有类对象所共享,不属于某个具体的对象,存放在静态区
代码如下:
#include<iostream>
using namespace std;
class A
{
public:
	A() 
	{
		++n;
		++m;
	}
	A(const A& t)
	{
		++n;
		++m;
	}
	~A()
	{
		--m;
	}
private:
	int a;//4 byte
	static int n;
	static int m;
};
int main()
{
	cout << sizeof(A) << endl;
	return 0;
}

2.静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明

解析思路:
当我们要计算A这个类,累计创建了多少个对象(用n表示),正在使用的多少个对象(用m表示)
以之前的知识,我们首先会在全局定义两个变量

 经过以下代码验证之后,我们发现,如果定义全局的变量,会被外面随意修改

       

        此时的话,我们试下把n和m定义在class A的private内,但是这样每一个对象在定义的时候,都会创建一个n和m,此时n和m是每一个对象的成员了,不是用来统计有几个对象,明显不能这样定义。

这时候如果被static修饰,这两个成员变量就位于静态区了,叫做静态成员变量,需要注意的地方有:

 代码如下:

class A
{
public:
private:
	int a;//4 byte
	static int n;//静态成员的声明
	static int m;//静态成员的声明
};
//在类外面定义
int A::n = 0;
int A::m = 0;

还有要注意的;

3. 类静态成员即可用 类名::静态成员 或者 对象.静态成员来访问 

静态成员变量被public修饰时:

 代码如下:

include<iostream>
using namespace std;
class A
{
public:
	A()
	{
		++n;
		++m;
	}
	A(const A& t)
	{
		++n;
		++m;
	}
	~A()
	{
		--m;
	}
//private:
	static int n;
	static int m;
};
// 静态成员变量的定义初始化
int A::n = 0;
int A::m = 0;

int main()
{
	A aa1;
	cout << A::n << " " << A::m << endl;//1.通过类名突破类域进行访问
	cout << aa1.n << " " << aa1.m << endl; //2.通过类对象突破类域进行访问
	A* ptr = NULL;
	cout << ptr->n << " " << ptr->m;//3.通过空指针解引用成员突破类域
}

当静态成员变量被private修饰时:

        我们当然可以定义被public修饰的成员函数,然后此时被static修饰的两个静态成员n和m通过创建对象aa1,接着aa1.Print()就可以打印出对象的个数,

        但如果我定义一个匿名对象,接着调用Print函数,这时候会多出一个n(累计创建的对象),干扰打印的逻辑了。

我们可以借鉴上面静态成员变量突破类域的方式,引出我们静态成员函数的三种突破类域的方式

代码如下: 

#include<iostream>
using namespace std;
class A
{
public:
	A()
	{
		cout << "A()" << endl;
		++n;
		++m;
	}
	A(const A& t)
	{
		++n;
		++m;
	}
	~A()
	{
		--m;
	}
	//静态成员函数的特点:没有this指针
	static int GetM()
	{
		return m;
	}
	static void Print()
	{
		//x++;//不能访问非静态,因为没有this
		cout << m << " " << n << endl;
	}
private:
    //这样定义不行,这样的话每一个对象都有一个n和m,
    //int m;
	//int n;
	// 不符合题意,因为这是来统计对象个数的


	//静态成员变量属于所有A对象,属于整个类
	//声明
	//累积创建了多少个对象
	static int n;
	//正在使用的还有多少个对象
	static int m;
};

int A::n = 0;
int A::m = 0;

int main()
{
	A aa;
    
//三种突破类域的方式
	A::Print();//通过类名调用静态成员函数进行访问
	aa.Print();//通过实例化的对象调用成员函数进行访问
	A* ptr = NULL;
	ptr->Print();//通过空指针调用静态成员函数进行访问

	return 0;
}
4. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员

代码如下:

//4. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
#include<iostream>
using namespace std;
class A
{
public:
	static void Print()
	{
		cout << x++ << endl;
	}
private:
	 int x;//非静态成员变量
	 static int a;//静态成员变量
};
int main()
{
	A x;
	x.Print();
}
5. 静态成员也是类的成员,受public、protected、private 访问限定符的限制
【问题】
1. 静态成员函数可以调用非静态成员函数吗?
答:不能 , 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
2. 非静态成员函数可以调用类的静态成员函数吗?
答:可以。 因为静态成员函数和非静态成员函数都在类中,在类中不受访问限定符的限制。
代码如下:
#include<iostream>
using namespace std;
class A
{
public:
	void Notstatic()
	{
		Print();//<-------非静态调用调用静态 
	}
    //两种写法
	static void Print()
	{
		cout << a << endl;
	}
	/*static int Print()
	{
		cout << a << endl;
		return a;
	}*/
private:
	 int x;//非静态成员变量
	 static int a;//静态成员变量
};
int A::a = 10;
int main()
{
	A x;
	x.Notstatic();
}

执行:

面试题

1. 1+2+3+...+n ,要求不能使用乘除法、 for while if else switch case 等关键字及条件判
断语句: 求1+2+3+...+n_牛客题霸_牛客网 (nowcoder.com)
#include<iostream>
using namespace std;
class Sum//定义一个名为Sum的类
{
public:
    Sum()//构造函数,当创建Sum对象时自动调用
    {
        _ret +=_i;// 每次构造函数被调用时,将静态成员变量_i的当前值累加到静态成员变量_ret上
        _i++; //紧接着递增静态成员变量_i的值
    }
    static int GetRet()//定义一个静态成员函数GetRet,用于获取静态成员变量_ret的值
    {
        return _ret;//直接返回静态变量_ret的值
    }
private:
//定义两个静态私有成员变量
// 静态成员变量属于类,不是某个对象所有,而是所有对象共享,并且在整个程序生命周期内只初始化一次
    static int _i;//初始化为1,每次构造函数调用时递增
    static int _ret;// 初始化为0,用于累计构造函数调用次数
};

//对静态成员变量进行初始化(定义)
int Sum::_i = 1;
int Sum::_ret = 0;
//定义另一个名为Solution的类
class Solution {
public:
    // 定义成员函数Sum_Solution,接收一个整数参数n
    int Sum_Solution(int n) {
        Sum a[n];
        return Sum::GetRet();
    }
};