static 静态局部对象、static类成员、命名冲突与static修饰符

本文详细解释了静态局部对象的概念及特点,包括其作用域、生命周期等,并通过示例展示了如何使用静态局部对象。此外,还介绍了静态类成员的特性、使用场景及注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

static静态局部对象

一个变量如果位于函数的作用域内,但生命期却跨越了这个函数的多次调用。 确保不迟于在程序执行流程第一次经过该对象的定义语句时进行初始化。这种对象一旦被创建,在程序结束前都不会被撤销。当定义静态局部对象的函数结束时,静态局部对象不会撤销。在该函数被多次调用的过程中,静态局部对象会持续存在并保持它的值。

作用域:从定义处到包含该变量的定义的块的结束处

例:

 

  1. size_t count_calls()  
  2.   
  3. {  
  4.   
  5.     static size_t ctr = 0;  
  6.   
  7.     return ++ctr;  
  8.   
  9. }  
  10.   
  11. int main()  
  12.   
  13. {  
  14.   
  15.     for (size_t i = 0; i != 10; ++i)  
  16.   
  17.         cout << count_calls() << endl;  
  18.   
  19.     return 0;  
  20.   
  21. }  

 

这个程序会一次输出1到10的整数。在第一次调用函数count_calls之前,ctr就已创建并赋予初值0。


static类成员

对于特定类类型的全体对象而言,访问一个全局对象有时是必要的。然而,全局对象会破坏封装。

通常,非static数据成员存在于类类型的每个对象中。不像普通的数据成员,static数据成员独立于该类的任意对象而存在;每个static数据成员是与类关联的对象,并不与该类的对象相关联。

普通成员总是与对象相关联,是某个对象的组成部分;而static成员与类相关联,由该类的全体对象所共享,不是任意对象的组成部分。

因为static成员是类的组成部分但不是任意对象的组成部分,因此staitc成员函数没有this形参,它可以直接访问所属类的static成员,但不能直接使用非static成员。static成员函数不能被声明为const,也不能被声明为虚函数。

定义static成员:在成员声明前加上关键字static将成员设为static。static成员遵循正常的公有/私有访问规则

使用类的static成员:可以通过作用域操作符从类直接调用static成员,或者通过对象、引用或指向该类类型对象的指针间接调用。

当在类的外部定义static成员时,无须重复指定static保留字,该保留字只出现在类定义体内部的声明处

static数据成员必须在类定义体的外部定义。不像普通数据成员,static成员不是通过类构造函数进行初始化,而是应该在定义时进行初始化。

特殊的整形const static成员:

一般而言,类的static成员,像普通数据成员一样,不能在类的定义体中初始化。相反,static数据成员通常在定义时才初始化。这个规则的一个例外是,只要初始化式是一个常量表达式,整型const static数据成员就可以在类的定义体中进行初始化。const static数据成员在类的定义体中初始化时,该数据成员仍必须在类的定义体之外进行定义(不必再制定初始值)。

static数据成员的类型可以是该成员所属的类类型。非static成员被限定声明为其自身类对象的指针或引用:

 

  1. class Bar {  
  2.   
  3. private:  
  4.   
  5.     static Bar mem1;        // ok  
  6.   
  7.     Bar *mem2;                 // ok  
  8.   
  9.     Bar mem3;                 // error  
  10.   
  11. }  

 

类似的,static数据成员可用作默认实参:

 

  1. class Screen {  
  2.   
  3. public:  
  4.   
  5.     Screen& clear(char = bkground);  
  6.   
  7. private:  
  8.   
  9.     static const char bkground = '#';  
  10.   
  11. }  

 

非static数据成员不能用作默认实参,因为它的值不能独立于所属的对象而使用。


命名冲突与static修饰符

static修饰符是一个能够减少命名冲突的有效工具。

编译器会对静态函数和静态变量的名称做一定改变,将它们也作为外部对象。由于经过了“名称修饰”,所以它们不会与其他源程序文件中的同名函数或同名变量发生命名冲突。

例如,一下声明语句

static int a;

其含义与下面的语句相同

int a;

只不过,a的作用域限制在一个源文件内,对于其他源文件,a是不可见的。因此,如果若干个函数需要共享一组外部对象,可以将这些函数放到一个源文件中,把它们需要用到的对象也都在同一个源文件中以static修饰符声明。

static修饰符不仅适用于变量,也适用于函数。如果函数f需要调用另一个函数g,而且只有函数f需要调用函数g,我们可以把函数f与函数g都放到同一个源文件中,并且声明函数g为static:

.

.

.

 

  1. static int  
  2. g(int x)  
  3. {  
  4. /* g 函数体 */  
  5. }  
  6.   
  7. void f()  
  8. {  
  9. /* 其他内容 */  
  10. b = g(a);  
  11. }  

 

.

.

.

.

.

.

我们可以在多个源文件中定义同名的函数g,只要所有的函数g都被定义为static,或者仅仅只有其中一个函数g不是static。因此,为了避免可能出现的命名冲突,如果一个函数仅仅被同一个源文件中的其他函数调用,我们就应该声明该函数为static。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值