深入理解关键字:const、static

const

对于const关键字,我们习惯性的将它直接看作常量,但当你编译下面代码时,会发现与我们之前的理解有所偏差:

const int SIZE;
int arr[SIZE];

//.c	不能通过
//.cpp	顺利运行

在定义数组时,必须指定数组元素个数为常量,但在C中却不能通过,以此可以推翻const修饰的值是常量。参考《C语言深度剖析》,可以将const修饰的值看作readonly属性,而C++之所以可以通过,是因为在C++中拓展了对const的含义。

下面针对const在不同编译环境下做深入理解:

- C
修饰一般变量 —只读变量
修饰数组—只读数组

//定义同时必须初始化
//const 与 类型名可交换顺序; const修饰的变量存放在 .rodata段,只读数据段

const int i = 10;
int const arrar[3] = {1, 2, 3};

修饰函数参数—不可改变
修饰函数返回值—不可改变

void func(const char* s);
const char* func();

修饰指针—编译器解析时忽略类型名,可以看作除类型名之外const修饰离其最近的

//下面我针对不同情况举例分析:
const int *p;	//const修饰*p,即p指向内容不可变
int const *p;	//const修饰*p
int *const p;	//const修饰p,即p本身不可变
const int *const p;//前一个const修饰*p,	后一个const修饰p

注:
对于C中const修饰的值并不是真正安全的(即真正只读/不可改变),通过下面举例分析便可以得到原因:

const int i = 10;
int *p = i;	
//在C编译其中默认支持用const int*类型去初始化int *类型
//诸如此类,那么我们必然会考虑到通过指针p可以去改变i的值
*p += 10;
//此时,i的值便被改变了

1.只读:更安全的宏替换
2.不可改变:实质上是指不可直接去改变。

- C++
对于C++来说,相比C对const扩展了不同含义。
扩展1、
常量:定义同时初始为立即数。
常变量:初始值为变量,则在编译时期不确定。

int a = 10;
const int N = 10;//N为常量
const int M = a; //M为常变量

//预编译阶段直接进行简单宏替换,
int b = N; 	// int b = 5;
int c = M;	// int c = a;(在编译时期不确定)

扩展二、
任何试图将一个非const对象的指针指向const对象的动作,都将引起编译错误。

const int *a = 10;
const int *p = a;
int const *q = a;
//此时p和q通过const修饰限定其指向内容不可改变,即保证了a的安全性。
//但p和q自身指向可以改变,不过也对a毫无影响了。

使用const的必要性:
1.更安全的宏替换,减少不必要的内存分配、存储与读取。
const与define比较
2.代码可读性与可维护性。
将特殊值或对象通过全局只读变量代替,易于辨识和后期修改。


static

修饰一般变量
首先,对于static修饰的变量,均有以下特点:

  • 默认值为0
  • 按程序的生命周期来分配和释放变量
  • 同所有未初始化的全局变量一样均放在 .bss段
  • 初始化:
    编译阶段—静态初始化放置在.bss段默认为0;
    运行阶段—动态初始化仅在首次调用处进行内存分配并赋值。

1、 全局静态变量:在全局变量前加上static,使该变量仅在当前文件可用。
与普通全局变量区别:限制了所修饰变量的作用域

2、局部静态变量:在局部变量前加上static,使该变量在当前函数体内恒有效,即仅首次调用该函数时对此变量进行初始化,并且直至程序运行结束才释放此变量。
与普通局部变量区别:拓展了所修饰变量的生命周期

//下面通过代码实际测试一下:
static int a;
static int b  = 0;
//这种用户直接将b初始化为0的操作与编译器对a的处理是一样的,因此也会将b放置在.bss段

void func()
{
	static int i = 1;
	int j = 1;
	i++;
	j++;
	cout<<i<<j<<endl;
}
int main()
{
	cout<<a<<endl;//打印a=0
	func();//打印i = 2; j = 1
	func();//打印i = 3; j = 1
}

修饰数组

  • 数组内元素会默认初始化为0

修饰指针 类似修饰一般变量,可用于回调函数

修饰函数

  • 函数只能在当前文件中被调用,即限定函数作用域
  • 函数调用结果不会修改任何非静态成员。

在C++中对static的扩充:
1、修饰对象:该对象在构造同时其成员相应内存都被初始化为0。
类内/类模板中static修饰的成员变量/对象,必须在类外进行初始化,其原因就是在编译阶段static所修饰的变量仅保存在.bss段中,而且对于类模板来说,只有在调用时才会对相应成员进行实例化一份,因此在运行期间可能会出现变量名相同产生错误,而对其初始化就是起到占位作用。

2、修饰成员函数:静态成员函数没有this指针,只能访问静态数据成员。
默认静态成员函数

3、修饰成员变量:限定该成员有且只能有一个实例化对象,即对每个类类型仅有一份拷贝,由该类类型的所有对象共享访问。
适用于单例模式:

//下面就实现一个简单的饿汉模式示例:
class signle
{
public:
	static single *getInstance()
	{
		if(pInstance == NULL)
		{
			if(pInstance == NULL)
				pInstance = new signle();
		}//双重判断保证多线程安全
		return pInstance ;
	}
private:	
	single (){}
	static single *pInstance ;
};
single *single::pInstance = NULL;	

//此时通过对象指针查看对象地址会发现均指向同一块内存空间
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值