静态成员变量与静态成员函数

在C++的类中,静态成员是属于整个类的而不是某个对象,静态成员变量只存储一份供所有对象共用。所以在所有对象中都可以共享它。使用静态成员变量实现多个对象之间的数据共享不会破坏隐藏的原则,保证了安全性还可以节省内存。

静态成员变量/函数的定义或声明要加个关键static。静态成员可以通过双冒号来使用即<类名>::<静态成员名>

例子 1:

class Point
{
public:	
    void init() {}
    static void output() {}
};

int main(int argc, char const *argv[])
{
    Point::init();
    Point::output();
    return 0;
}

报错信息:a nonstatic member reference must be relative to a specific object

结论 1: 不能通过类名来调用类的非静态成员函数, 而只能通过一个实例。

例子 2:

将上面的 main() 改为

int main(int argc, char const *argv[])
{
	Point pt;
	pt.init();
	pt.output();

    return 0;
}

没有问题。

结论 2: 类的对象可以使用静态成员函数和非静态成员函数。

例子 3:在类的静态成员函数中使用类的非静态成员变量

class Point
{
public:
    void init() {}
    static void output()
    {
        cout << _x << endl;
    }

private:
    int _x;
};

报错信息: a nonstatic member reference must be relative to a specific object

因为静态成员函数属于整个类,在类实例化对象之前就已经分配空间了,而类的非静态成员必须在类实例化对象后才有内存空间,所以这个调用就出错了,就好比没有声明一个变量却提前使用它一样。

结论 3: 静态成员函数中不能引用非静态成员

例子 4: 在类的非静态成员函数中调用静态成员函数

class Point
{
public:	
	void init()
	{  
		output();
	}
	static void output()
	{
	}
};

int main(int argc, char const *argv[])
{
    Point pt;
    pt.init();

    return 0;
}

编译通过

结论 4:类的非静态成员函数可以调用静态成员函数,但是反之不能

例子 5:

class Point
{
public:	
	Point()
	{  
		_point_count++;
	}
	~Point()
	{
		_point_count--;
	}
	static void output()
	{
		cout << _point_count;
	}
private:
	static int _point_count;
};

int main(int argc, char const *argv[])
{
    Point pt;
    pt.output();

    return 0;
}

报错信息:对‘Point::_point_count’未定义的引用

修改:在类外加入,int Point::_point_count = 5;

原因:静态成员变量存储在全局数据区。static 成员变量的内存空间既不是在声明类时分配,也不是在创建对象(定义)时分配,而是在初始化时分配。类的静态成员变量必须初始化,而且只能在类体外进行(在类内只是声明)。否则,编译能通过,链接不能通过。需要定义并初始化静态成员变量。初始化时可以赋初值,也可以不赋值。如果不赋值,那么会被默认初始化,一般是 0。静态数据区的变量都有默认的初始值,而动态数据区(堆区、栈区)的变量默认是垃圾/随机值。


题目是静态成员变量与静态成员函数,所以讲道理到这里也就结束了。下面是面向对象的过程:

在全局变量前,加上关键字 static,该变量就被定义成为一个静态全局变量。

静态全局变量具有以下特点:

  1. 该变量在全局数据区分配内存;
  2. 未经初始化的静态全局变量会被程序自动初始化为0(自动变量的自动初始化值是随机的);
  3. 静态全局变量在声明它的整个文件都是可见的,而在文件之外是不可见的;  
  4. 静态变量都在全局数据区分配内存,包括后面将要提到的静态局部变量。对于一个完整的程序,在内存中的分布情况如下:[代码区][全局数据区][堆区][栈区],一般程序的由new产生的动态数据存放在堆区,函数内部的自动变量存放在栈区,静态数据(即使是函数内部的静态局部变量)存放在全局数据区。自动变量一般会随着函数的退出而释放空间,而全局数据区的数据并不会因为函数的退出而释放空间。

在局部变量前,加上关键字static,该变量就被定义成为一个静态局部变量。

静态局部变量有以下特点:

  1. 静态局部变量在全局数据区分配内存;
  2. 静态局部变量在程序执行到该对象的声明处时被首次初始化,即以后的函数调用不再进行初始化;
  3. 静态局部变量一般在声明处初始化,如果没有显式初始化,会被程序自动初始化为0;
  4. 静态局部变量始终驻留在全局数据区,直到程序运行结束。但其作用域为局部作用域,当定义它的函数或语句块结束时,其作用域随之结束;

在函数的返回类型前加上static关键字,函数即被定义为静态函数。静态函数与普通函数不同,它只能在声明它的文件当中可见,不能被其它文件使用。

定义静态函数的好处:(类似于静态全局变量)

  1. 静态函数不能被其它文件所用;
  2. 其它文件中可以定义相同名字的函数,不会发生冲突;
  3. 静态成员函数主要用来访问静态数据成员而不能访问非静态成员。