static关键字总结

一、static两个作用:1、限定作用域(隐藏)  2、保持变量内容持久化

1、限定作用域(隐藏)

//a.c
char a = 'A'; // 全局变量
void msg()  //全局成员函数
{
     printf("Hello\n");
}


//main.c
int main()
{
     extern char a; // 调用全局变量
     printf("%c ", a);
     (void)msg();  //调用成员函数
     return 0;
}

所有未加static前缀的全局变量和函数都具有全局可见性,其它的源文件也能访问。如果加了static,就会对其它源文件隐藏。

例如在a和msg的定义前加上static,main.c就看不到它们了。利用这一特性可以在不同的文件中定义同名函数和同名变量,而不必担心命名冲突

2、保持变量内容的持久

存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。

#include 
 
int fun(){
    static int count = 10; //在第一次进入这个函数的时候,变量a被初始化为10!并接着自减1,以后每次进入该函数,a
    return count--; //就不会被再次初始化了,仅进行自减1的操作;在static发明前,要达到同样的功能,则只能使用全局变量:    
 
}
 
int count = 1;
 
int main(void)
{
     printf("global\t\tlocal static\n");
     for(; count <= 10; ++count)
               printf("%d\t\t%d\n", count, fun());
     return 0;
}

二、《Effective C++》条款04  不同编译单元内定义的non-local static对象”的初始化

如果一个编译单元的non-local static对象初始化使用了另外一个编译单元的non-local static对象,它所用到的这个对象可能尚未被初始化,因为C++对“定义在不同编译单元内的non-local static对象”初始化次序无明确规定。

class FileSystem{
public:
std::size_t numDisks()const;
};
extern FileSystem tfs;//定义在global作用域
 
class Directory{
public:
	Directory( params )
	{
		std::size_t disks=tfs.numDisks();
	}
};
Directory tempDir( params);

std::size_t disks=tfs.numDisks();如果tfs初始化晚于tempDir,那么tempDir会使用尚未初始化的tfs。tfs和tempDir是不同的人写的源码,定义在不同的编译单元,无法确定哪一个先初始化。

解决办法:

使用local static 对象,首次使用时初始化,返回其引用即可,以后无须再次初始化。用函数tfs()代替对象tf.

class FileSystem{}
FileSystem& tfs()//函数代替对象,返回引用指向该对象
{
    static FileSystem fs;//第一行定义初始化一个局部static对象
    return fs;           //第二行返回对象
}

class Directory{};
public:
   Directory::Directory( params )
    {
        std::size_t disks=tfs().numDisks();//调用函数
    }
};
Directory& tempDir()
{
    static Directory td;
    return td;
}

使用函数返回的“指向static对象”的references,而不再是static对象本身。

三、类的静态成员

出现原因:静态成员可以实现多个对象之间的数据共享,并且使用静态数据成员还不会破坏隐藏的原则,即保证了安全性。它是类的类的所有对象中共享的成员,而不是某个对象的成员。使用静态数据成员可以节省内存,因为它是所有对象所公有的,因此,对多个对象来说,静态数据成员只存储一处,供所有对象共用。静态数据成员的值对每个对象都是一样,但它的值是可以更新的。只要对静态数据成员的值更新一次,保证所有对象存取更新后的相同的值,这样可以提高时间效率。

数据成员可以分为静态变量、非静态变量两种。

  • 静态成员:静态类中的成员加入static 修饰符,即是静态成员,可以使用类名+静态成员名访问此静态成员,因为静态成员存在于内存(全局数据区),而非静态成员需要实例化才会分配内存,所以静态成员不能访问非静态成员,因为静态成员存在于内存,所以非静态成员可以直接访问类中的静态成员
  • 非静态成员:所以没有加static的成员都是非静态成员,当类被实例化后,可以通过实例化的类名进行访问,非静态成员的生存期决定于该类的生存期,而静态成员则不存在生存期的概念,因为静态成员始终驻留在内存中。

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

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

一般在程序中,由new产生的动态数据区放在堆区中,函数内部的自动变量存放在栈区。自动变量一般会随着函数的退出而释放空间,静态数据(即使是函数内部的静态局部变量)也存放在全局数据区中。全局数据区的数据并不会因为函数的退出而释放空间。 

 

  • 代码区
  • 全局数据区
  • 堆区
  • 栈区
#include 
#include 
 
using namespace std;
 
class test
{
private:
    static int m_value;		//定义私有类的静态成员变量
 
public:
    test()
    {
    	m_value++;
    }
 
    static int getValue()		//定义类的静态成员函数
    {
    	return m_value;                //静态成员函数只能调用静态成员变量。
    }
};
 
int test::m_value = 0;		//类的静态成员变量必须先初始化再使用。
int main()
{
    test t1;
    test t2;
    test t3;
 
    cout << "test::m_value2 = " << test::getValue() << endl;	//通过类名直接调用公有静态成员函数,获取对象个数
    cout << "t3.getValue() = " << t3.getValue() << endl;		//通过对象名调用静态成员函数获取对象个数
    cout<<"t3.test()="<

 

对类的静态成员变量和成员函数作个总结:

一。静态成员函数中不能调用非静态成员。(未对象实例化前,非静态成员未分配内存)

二。非静态成员函数中可以调用静态成员。因为静态成员属于类本身,在类的对象产生之前就已经存在了,所以在非静态成员函数中是可以调用静态成员的。

三。静态成员变量使用前必须先初始化(如int MyClass::m_nNumber = 0;),否则会在linker时出错。

参考:

www.runoob.com/cplusplus/cpp-static-members.html

https://www.cnblogs.com/VVingerfly/p/7128162.html

https://www.cnblogs.com/heyonggang/p/3296378.html

https://blog.csdn.net/lms1008611/article/details/81408236

 

 

你可能感兴趣的:(C++)