static关键字修饰成员变量与成员函数

1. static概念

声明static的类成员称为类的静态成员,用static修饰的成员变量,称为静态成员变量;用static修饰的成员函数,称为静态成员函数,都存放在堆区。

静态成员变量一定要在类外进行初始化

为什么静态成员变量一定要在类外进行初始化呢?

  1. 在类中,仅仅是声明了静态变量(告诉我们有这个成员变量),并没有定义(定义需要分配内存)。

  2. 声明只是表明了变量的数据类型和属性,并不分配内存;定义则需要分配内存。 注意:如果在类里面这么写 int a ;那么既声明了变量,也定义了变量,两者合在一起了。

  3. 静态成员是“类级别的”,它和类的地位等同,而普通成员是“对象(实例)级别的”。类级别的成员,先于该类的任何对象而存在,是属于所有对象的,被该类的所有对象共享。

  4. 现在,咱们假定要实例化该类的一个对象,那么会发生什么事情呢?

    静态成员肯定要出现在这个对象里面的,对吧?这时候才去定义那个静态成员吗?显然不合适!因为,比如有另外一个线程也要创建该类的对象,那么也要按照这个方式去定义那个静态成员。
    这可能会产生两种情况:
    A. 重复定义;
    B. 就算不产生重复定义的情况,也会产生竞争,造成死锁。
    显然编译器不能这么干。很合理的解决办法,就是在类的外部事先把它定义好,然后再供所有的对象共享。

class A
{
    
    
public:
	static int _a;
	static int _b;
};

int A::_a = 10;   // 定义静态成员变量,同时也初始化。
int A::_b;   // 定义静态成员变量,不初始化也可以。

int main()
{
    
    
	A T1;
	cout << T1._a << endl;  // 10
	cout << A:: _b << endl;  // 0
	return 0;
}

静态成员函数既可以在类内定义,也可以在类外定义,类外定义不需要加static。

普通成员函数可以访问所有成员(包括成员变量和成员函数),静态成员函数只能访问静态成员。

编译器在编译一个普通成员函数时,会隐式地增加一个形参 this,并把当前对象的地址赋值给 this,所以普通成员函数只能在创建对象后通过对象来调用,因为它需要当前对象的地址。而静态成员函数可以通过类来直接调用,编译器不会为它增加形参 this,它不需要当前对象的地址,所以不管有没有创建对象,都可以调用静态成员函数。

普通成员变量占用对象的内存,静态成员函数没有 this 指针,不知道指向哪个对象,无法访问对象的成员变量,也就是说静态成员函数不能访问普通成员变量,只能访问静态成员变量。

普通成员函数必须通过对象才能调用,而静态成员函数没有 this 指针,无法在函数体内部访问某个对象,所以不能调用普通成员函数,只能调用静态成员函数。

class A
{
    
    
public:
	A() {
    
     ++_count; }

	A(const A& t) {
    
     ++_count; }
	
	~A() {
    
     --_count; }
	
	static int GetACount()    // 类内定义,只能访问静态成员
	{
    
    
		return _count; 
	}

private:
	static int _count;
};

int A::_count = 0;


void TestA()
{
    
    
	cout << A::GetACount() << endl;   // 可以直接调用类
	A a1, a2;
	A a3(a1);
	cout << a3.GetACount() << endl;   // 也可以直接使用对象调用
}

int main()
{
    
    
	TestA();

	return 0;
}

总结:
静态成员函数与普通成员函数的根本区别在于:普通成员函数有 this 指针,可以访问类中的任意成员;而静态成员函数没有 this 指针,只能访问静态成员(包括静态成员变量和静态成员函数)。

2. 使用细节

特性:

  1. 静态成员为所有类对象共享,存放在静态区(在对象实例化之前就已经定义了)。
  2. 静态成员变量必须在类外定义,定义时不添加static关键字。
  3. 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问。
  4. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员。
  5. 静态成员也是类的成员,受public、protected、private 访问限定符的限制。

3. 易错点

问题1:
静态成员函数可以调用非静态成员函数吗?
不可以,因为静态成员函数没有this指针,普通成员函数必须有相应的对象地址(this)才能调用,因为普通函数里面要用this来访问对象。

问题2:
非静态成员函数可以调用类的静态成员函数吗?
可以,静态成员函数属于整个类,既可以使用类域(A::)进行调用,也可以使用对象(a1.)进行调用。

猜你喜欢

转载自blog.csdn.net/weixin_45153969/article/details/132791791