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

简介: 1. static概念声明 为static的类成员称为类的静态成员,用static修饰的成员变量,称为静态成员变量;用static修饰的成员函数,称为静态成员函数,都存放在堆区。静态成员变量一定要在类外进行初始化。

1. static概念

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

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

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


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


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


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


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


静态成员肯定要出现在这个对象里面的,对吧?这时候才去定义那个静态成员吗?显然不合适!因为,比如有另外一个线程也要创建该类的对象,那么也要按照这个方式去定义那个静态成员。

这可能会产生两种情况:

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.)进行调用。

目录
相关文章
|
存储 Java
static关键字
static关键字
54 0
|
4月前
|
编译器 C++
【C++】详解初始化列表,隐式类型转化,类静态成员,友元
【C++】详解初始化列表,隐式类型转化,类静态成员,友元
|
6月前
|
Java
static关键字详解~
static关键字详解~
44 0
|
6月前
|
存储 监控 编译器
【C++】static关键字及其修饰的静态成员变量/函数详解
【C++】static关键字及其修饰的静态成员变量/函数详解
156 3
|
6月前
|
存储
成员变量和类变量的区别:
成员变量和类变量的区别:
104 0
|
存储 Cloud Native Linux
C++ static关键字
C++ static关键字
|
存储 程序员 C语言
【C】static关键字详解
static的汉语意思是静态的,在C语言中static关键字可以用来修饰局部变量、全局变量和函数。
|
Java C语言 C++
static关键字详解(C/C++)
static关键字详解(C/C++)
【C++之成员函数】类外定义成员函数
【C++之成员函数】类外定义成员函数