const和static的用法

const 用法

const 修饰局部变量
// 等效的写法
const int n = 1; // n 必须初始化
int const n = 1; // n 必须初始化
const 修饰常量静态字符串
const char* str="fdsafdsa";

如果没有const的修饰,我们可能会在后面有意无意的写str[4]=’x’这样的语句,这样会导致对只读内存区域的赋值,然后程序会立刻异常终止。有了const,这个错误就能在程序被编译的时候就立即检查出来,这就是const的好处。让逻辑错误在编译期被发现。

const 修饰指针
int n;
int * const p = &n; // 指针常量,指针只能在初始化时指向某一对象,但可以通过指针修改所指对象的值
const int * p = &n; // 常量指针,指针可以指向任意对象,但不能通过指针修改所指对象的值
int const * p = &n; // 常量指针,等效
const 修饰类对象/引用/指针
class TEMP {
	void func1();
    void func2() const;
};
const TEMP temp;
temp.func1(); //错误;
temp.func2(); //正确;
  1. 不能改变对象的任何成员变量
  2. 不能调用任何非const成员函数,因为任何非const成员函数都会有修改成员变量的可能
const 修饰类数据成员
  1. 不能被修改
  2. 只能在类初始化列表中被赋值

总结:只能在初始化列表中初始化的情况

  1. const成员变量
  2. 引用变量
  3. 基类构造函数
const 修饰类成员函数
void func (void) const;
  1. 不能修改类的任何非静态数据成员(可以修改静态数据成员)
  2. 不能调用类的任何非const函数(可以调用const成员函数)
  3. 对于const类对象,只能调用类中的const成员函数,所以const修饰成员函数的作用主要就是限制对const对象的使用。
const常量与define宏定义的区别
  1. 编译器处理方式不同

    • define宏是在预编译阶段展开

    • const常量是编译运行阶段使用

  2. 类型和安全检查不同

  • define宏没有类型,不做任何类型检查,仅仅是展开
  • const常量有具体的类型,在编译阶段会执行类型检查,可以进行调试
  1. 存储方式不同
  • define宏不占内存,宏只是在预处理时展开,但展开后占内存,每次替换都是一次内存拷贝

  • const定义的只读变量在程序运行过程中只有一份拷贝(因为它是全局的只读变量,存放在静态区),而#define定义的宏常量在内存中有若干个拷贝。

  1. 总结

    • const节省了空间,避免了不必要的内存分配,同时提高了效率。编译器通常不为普通的const只读变量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的值,没有了存储与读内存的操作,使得它的效率也很高。C++中是不太推荐用宏的,尽量少用.因为C++是强类型的语言,希望通过类型检查来降低程序中的很多错误,而宏只是在编译期前做简单替换,绕过了类型检查,失去了强类型系统的优势支撑。
mutable关键字
class ST { 
public:
    int a; 
    mutable int showCount; 
    void Show()const; 
};
void ST::Show()const { 
	//a=1;//错误,不能在const成员函数中修改普通变量 
	showCount++;//正确 
}

在C++中,mutable是为了突破const的限制而设置的。被mutable修饰的变量,将永远处于可变的状态,即使在一个const函数中,甚至结构体变量或者类对象为const,其mutable成员也可以被修改。mutable只能修饰非静态数据成员。

const_cast
const_cast<type_id> (expression)
  1. 该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外, type_id和expression的类型是一样的
  2. 常量指针被转化成非常量的指针,并且仍然指向原来的对象
  3. 常量引用被转换成非常量的引用,并且仍然指向原来的对象
  4. const_cast一般用于修改底指针。如const char *p形式

static 变量

//main.c文件中
int a = 0; //全局变量
static int b=0;//静态全局变量
main() 
{ 
	int c; //局部变量
	static int d;//静态局部变量 
}
  • 全局变量

    具有全局作用域,全局变量只需在一个源文件中定义,其他文件就可以在使用extern外部声明后直接使用。未初始化时,默认为0。

  • 静态全局变量

    具有全局作用域,它与全局变量的区别在于如果程序包含多个文件的话,它作用于定义它的文件里,不能作用到其它文件里,即被 static 关键字修饰过的全局变量具有文件作用域。为初始化时,默认为0。

  • 局部变量

    具有局部作用域,它是自动对象(auto),它在程序运行期间不是一直存在,而是只在函数执行期间存在,函数的一次调用执行结束后,变量被撤销,其所占用的内存也被收回。未初始化时,默认值未定义。

  • 静态局部变量

    具有局部作用域,它只被初始化一次,自从第一次被初始化直到程序运行结束都一直存在。它始终驻留在全局数据区,直到程序运行结束。但其作用域为局部作用域,也就是不能在函数体外面使用它。未初始化时,默认值为0。

    一个静态局部变量的例子
    #include<stdio.h>
    static int j; //修饰静态的全局变量
    int funOne(void)
    {
            static int i = 0;//修饰静态的局部变量
            i++;
            return i;
    }
     
    int funTwo(void)
    {
            j = 0;
            j=j+2;
            return j;
    }
     
    int main()
    {
            int k = 0,m = 0,n = 0;
            for(k = 0;k < 5;k++)
            {
                    m = funOne();
                    n = funTwo();
                    printf("m=%d,n=%d\n",m,n);
            }
            return 0;
    }
    

    结果显示如下

    m=1,n=2

    m=2,n=2

    m=3,n=2

    m=4,n=2

    m=5,n=2

static 函数

函数的使用方式与全局变量类似,在函数的返回类型前加上static,就是静态函数。其特性如下:

  • 静态函数只能在声明它的文件中可见,其他文件不能引用该函数
  • 不同的文件可以使用相同名字的静态函数,互不影响

c++面向对象中static的使用特性

静态数据成员

在类内数据成员的声明前加上static关键字,该数据成员就是类内的静态数据成员。其特点如下:

  • 静态数据成员存储在全局数据区,静态数据成员在定义时分配存储空间,所以不能在类声明中定义
  • 静态数据成员是类的成员,无论定义了多少个类的对象,静态数据成员的拷贝只有一个,且对该类的所有对象可见。也就是说任一对象都可以对静态数据成员进行操作。而对于非静态数据成员,每个对象都有自己的一份拷贝。

由于上面的原因,静态数据成员不属于任何对象,在没有类的实例时其作用域就可见,在没有任何对象时,就可以进行操作

  • 和普通数据成员一样,静态数据成员也遵从public, protected, private访问规则
  • 静态数据成员的初始化格式:<数据类型><类名>::<静态数据成员名>=<值>
  • 类的静态数据成员有两种访问方式:<类对象名>.<静态数据成员名> 或 <类类型名>::<静态数据成员名>

同全局变量相比,使用静态数据成员有两个优势:

  • 静态数据成员没有进入程序的全局名字空间,因此不存在与程序中其它全局名字冲突的可能性
  • 可以实现信息隐藏。静态数据成员可以是private成员,而全局变量不能
静态成员函数

与静态数据成员类似,静态成员函数属于整个类,而不是某一个对象,其特性如下:

  • 静态成员函数没有this指针,它无法访问属于类对象的非静态数据成员,也无法访问非静态成员函数,它只能调用其余的静态成员函数或访问其余静态数据成员
  • 出现在类体外的函数定义不能指定关键字static
  • 非静态成员函数可以任意地访问静态成员函数和静态数据成员

总结

static是一个很有用的关键字,使用得当可以使程序锦上添花。当然,有的公司编码规范明确规定只用于本文件的函数要全部使用static关键字声明,这是一个良好的编码风格。

无论如何,要在实际编码时注意自己的编码习惯,尽量体现出语言本身的优雅和编码者的编码素质。

参考

https://www.jb51.net/article/118141.htm

https://www.cnblogs.com/qiaoconglovelife/p/5322521.html

https://www.bbsmax.com/A/pRdB8G06Jn/

https://blog.csdn.net/guotianqing/article/details/79828100

https://blog.csdn.net/weixin_42167759/article/details/80287748

May 24, 2020 PM 23:17 @DaYang

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值