C++基础之const系列

1. const有什么用途?

在 c程序中,const的用法主要有定义常量、修饰函数参数、修饰函数返回值等3个用处。

在c++程序中,它还可以修饰函数的定义体,定义类中某个成员为常态函数,即不改变类中的数据成员

被const修改的东西都要受到强制保护,可以预防意外的变动,能提高程序的健壮性。

2. const与#define相比有什么不同

它们都可以用来定义常量,但const比#define有更多优点:

(1) const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换中可能会产生意料不到的错误(边际效应)。

(2) 在c++中使用const常量而不使用宏常量,即const常量完全取代宏常量。

注解:c++编译器中,可以通过指针强转改变,也可以通过当然也可以const_cast去掉const(只读)属性。

#include <iostream>

using namespace std;
int a = 5;
const int l = a;
int main(){
    int *c = (int *)&l;
    *c = 100;
    cout<<l<<endl;
    return 0;
}   
结果是 100;

如果是下面这个:

#include <iostream>

using namespace std;
const int l = 5;
int main(){
    int *c = (int *)&l;
    *c = 100;
    cout<<l<<endl;
    return 0;
}   
<div><img src="file:///C:\Users\Administrator\AppData\Roaming\Tencent\Users\598144530\QQ\WinTemp\RichOle\N}$[`5A51[FS)R)9ACRWJ@4.png" alt="" /></div>

结果如下,所以右操作数为字面常量时,强转不安全

const只是在编译期的保护,编译器会检查const变量有没有被修改,如果有代码尝试修改一个const变量,编译器会报错。但是你总是可以通过直接访问地址的形式去修改它的值。取决于编译器的不同,它有可能被放在某种被操作系统保护的区域内,尝试写入会导致程序崩溃之类的错误。

编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。所以我们要大胆的使用。

当然,c++11也为我们引进了一个新的东西constexpr,constexpr是C++11中新增的关键字,其语义是“常量表达式”,也就是在编译期可求值的表达式。最基础的常量表达式就是字面值或全局变量/函数的地址或sizeof等关键字返回的结果,而其它常量表达式都是由基础表达式通过各种确定的运算得到的。constexpr值可用于enum、switch、数组长度等场合。其作用相当于static const。不过安全性更高。

constexpr的好处:

  1. 是一种很强的约束,更好地保证程序的正确语义不被破坏。
  2. 编译器可以在编译期对constexpr的代码进行非常大的优化,比如将用到的constexpr表达式都直接替换成最终结果等。
  3. 相比宏来说,没有额外的开销,但更安全可靠。
——————————————————————————————————————————————————————————————————————

const总结:

一、常量
        #define PI 3.1415926
        const double PI = 3.1415926
        用const修饰保证会对他进行类型识别等必要的编译器内部操作,比宏定义更合理, 但要注意,声明时必须初始化,特别是在类类型中,要记得在初始化列表中初始化。(详见effective C++)

二、与指针联系
         1、const int *p;
               p是指向const int的指针,所以不能用赋值语句对*p赋值;但可以对p本身赋值。
         2、int * const p=&i;
               p是指向int的const指针。p是const数据,所以其本身不可改变,而*p可以被赋值。 
             (注意和const int *p;的区别。)p被初始化为i的地址,i是变量,这是*p可赋值的原因。
        3、const int * const p=&i;
              p是一个const指针,其指向const数据i。p、*p都不能再被赋值。
             可以在初始化p指针时对其初始化。

三、与函数联系
        1、普通函数
              放在返回值前修饰返回值表示返回值必须保持其常量性,不能被更改;
              放在参数前修饰参数表示该参数必须保持其常量性,不能在函数体内被修改;
        2、类成员函数
              放在函数尾部,表示其在函数内并不修改对象的属性,只是读取等操作非更易型操作
             (当然声明类成员为易变类型另当别论)     (详见TCPL)

四、与类型联系
        当类的对象被声明成const类型后,它将不能调用更易型操作,所以很多成员函数有重载了的const版本

个人使用心得:

1. 要大胆的使用const,这将给你带来无尽的益处,但前提是你必须搞清楚原委;

2. 要避免最一般的赋值操作错误,如将const变量赋值,具体可见思考题;

3.在参数中使用const应该使用引用或指针,而不是一般的对象实例,原因同上;

4.const在成员函数中的三种用法(参数、返回值、函数)要很好的使用;

5.不要轻易的将函数的返回值类型定为const;

6.除了重载操作符外一般不要将返回值类型定为对某个对象的const引用;

7.任何不会修改数据成员的函数都应该声明为const 类型。


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值