Const 的作用及历史

const (computer programming) - Wikipedia

一、历史

按理来说,要想了解一件事物提出的原因,最好的办法就是去寻找当时的历史背景,以及围绕这件事所发生的故事。

可是非常抱歉,我并没没有找到C语言中const 提出的背景,但是一个可以参考的历史是,常量这种数据形式早在汇编语言中就有所体现,汇编语言中的constant 是一个确定的数值,在汇编阶段就可以确定直接编码在于指令代码中,不是保存在寄存器中的可以变化的量。

常量是需求,C 语言没理由不保留这个传统,自然而然的const 关键字出现了。

二、C和C++的异同点

顾名思义,const 最基础的作用就是保证数据不会被修改,仅仅可读而已。这就好比一份没有write 权限的文件一样,只能远观而已。

const 是C语言32个关键字(C++中有49个)中的一个,主要起类型修饰的作用,可以理解为变量的属性,比方说const int a = 10 从右往左看int a = 10 是定义并初始化了一个变量a 等于10,随后使用const 修饰这个变量,告诉编译器,这个变量是不可修改的。为了维护程序的安全性,由于const 一旦修饰就无法再更改了,那么const int a; 会生成一个值随机且永远无法修改的量,这样非常不安全,所以C 的编译器会要求你必须在定义的时候就立马初始化。从这里也可以看出const关键字的强硬之处。

到底const该放在哪?

在详细讨论const的用法之前,必须首先明白,const 是C语言中的一个类型限定符(type quailier),是类型的一个部分,且const 越靠近谁,就修饰谁是常量类型。

从C语言的基础数据类型来看,基本上可以抽象为一下几个类别

  • 基础数据类型(整型,浮点)

    • 对于基础数据类型,使用const就单纯定义为一个不可修改的量,此时由于不涉及其他的类型限制符,所以const放在哪里都是有效的
    • const int i = 10 \(\Leftrightarrow\) int const i = 10 但是一般const在前。
  • 指针类型(指针)

    • 相比于基础数据类型,指针类型存在很大的不同。
    1. 不使用const修饰的指针,此时表示该指针一定指向一个变量,当指向const修饰的变量是就会报错

      const int a = 10;
      int * ptr = a; // error
    2. const 放在 int *前时,表示指针类型是 const int 类型,那么依据指针类型的定义,该指针必定指向一个const int 类型的量,即常量。

      const int b = 100;
      const int * a = &b;
    3. const 放在 int * 后面时,int * const a ,显然根据常规的指针类型的定义,我们只能推测出这是一个指向int类型的指针,那么const起什么作用呢?(见如下代码)

      int c = 10, b = 20;
      const int b = 30;
      int * const a = &c; // 此处没有报错,证明*号前面是指针类型,这条真理没错
      //1. 可当我们尝试修改指向的时候
      a = &b;
      // 此处会报错!这表明const靠近变量名的时候表示指针指向一个变量后就无法更改了 //2. 如果一开始就不初始化int * const a呢?
      int * const a; // 此处会报错 //3. 如果尝试让他指向一个const量呢?
      int * const a = &b; // 此处会报错
    4. 以此类推可以得到一个指向const变量的无法修改指向的指针

      const int b = 10;
      const int * const a = &b;

      所以可以给出总结

      1. const 靠近变量名的时候表示指针必须指向一个类型与指针类型相同的变量
      2. 一旦指向就无法更改指向
      3. 无法指向常量
  • 复杂数据类型(枚举,结构,共用)

    针对复杂类型,由于出现了简单类型的嵌套,自然会有const 的嵌套关系,下面以结构体来举例子

    1. const嵌套在结构体内部时。
    typedef struct a {
    const int b;
    int c;
    }A; int main() {
    A aa;
    aa.b = 10; // 此处会报错
    }

    在C语言中,在结构体内部使用const修饰不会报错的,但是此变量再也无法修改,意味着这是一个无效量,既无法初始化,也无法修改(但是得益于C++的面向对象机制,即使如此我们还是可以定义const并且给他赋值)。

    1. 当定义结构体的时候使用const
    const A bb;

    此时也会报错,而且相对来说比上面还严重,此时结构体内部的所有值都是乱的,且无法修改。

而C++中由于引入了几种新的编程模式,const 的作用范围又进一步被扩充。

  • 类中属性与成员函数

    1. 结构体的遗留问题(即类的常量属性)

    这里先来解决前面C语言中的结构体问题,需求是想在结构体内部定义const变量,知道结构体内部的变量是无法直接初始化的,而C++中结构体可以理解为类,只不过权限不同而已,同样可以拥有构造函数。

    那么是不是可以在构造函数中初始化呢?(下面代码会报错)

    struct a {
    a() {
    b = 100;
    }
    const int b;
    };

    不是我们想的那样,不过也非常接近,对于初始化类的变量还有一种方法,使用初始化列表(类的初始化列表的优先级是非常高的)

    struct a {
    a() : b(100) {;} const int b;
    };

    或者还有

    struct a {
    const int b = 100;
    };

    利用C++特性直接赋值,而此段代码在C语言中会报错,这也是C与C++不同的一个地方。

    如此就完美解决了结构体const量 问题。

    1. 类的静态变量vs const 变量

    static 也是一个修饰符,确定的是变量的生存期。const觉得变量的可读性,有这样一条语句在类中和main函数中存在不同的意义

    static const int a;
    // 此语句在main中会报错,由于未初始化
    // 在类中不会

    这是由于static不会影响const的表达,在main函数中说明此变量就是const类型,确实需要立马赋值。而在类中可以不那么着急,可以把类中的static变量理解为一个申明,在类的外面或者里面直接定义都可以,不会报错。

    1. 函数const 以及类成员函数的const修饰

    普通函数的const

    函数const 首先想到的是const 变量返回值。但是这其实是没太大意义的

    const修饰返回值其实完全没有发挥作用,属于无效修饰。同样的使用const修饰形式参数的时候也是如此,并不会限定你传入的是const还是普通变量,本质在于这一过程发生原因是由于值传递,不论是返回const 还是使用const 修饰形式参数,内部都发生了变量的创建与赋值

    const修饰形参的例子,

    int fun(const int a) {
    // a = 10 会报错
    return a
    } int main() {
    int c = 10;
    int d = fun(c); // 不会报错
    }

    如上,c传入的时候是把c的值拿到,然后函数压栈,创建一个const int 变量a 且立马初始化为c的值,如此就在函数内部生成了一个const 变量。跟传入什么值完全没有关系。

    成员函数的const尾修饰

    这属于C++的特性,成员函数尾巴加上一个const 限制此函数对对象的修改,且提高了代码的可读性。

    class A {
    private:
    int a; public:
    static int B;
    int getA() const {
    A::B = 100; // 此处不会报错
    a = 100; // 这里会报错
    return a;
    }
    }; int A::B = 100;

    使用const修饰成员函数会使该函数变成const member function 此类型无法修改对象的数据,但是可以修改可修改的静态变量。

  • 引用

    引用相对来说没有指针那么多的变种,引用的const 修饰也仅仅局限于让引用变量无法修改指向这一点上。

  • 在补充一点

    const修饰类静态整型变量的时候可以在类内部直接初始化(浮点数仍然是不行的)。

C++11 关键字 const 到底怎么用?的更多相关文章

  1. 关键字const

    const关键字常和指针一起使用. 1,const给读代码的人传达非常有用的信息.比如一个函数的参数是const char *,你在调用这个函数时就可以放心地传给它char *或const char ...

  2. C语言关键字const作用及其应用

    只要学过C语言的,都有知道const这个关键字,知道是用来定义常量的,如果一个变量被const修饰,那么它的值就不能再被改变,那么还有什么其他作用呢? 一.const常用作用 1.修饰局部变量 con ...

  3. ES6中不得不说的关键字const

    上一节讲了let关键字,它是用来声明一个变量,只在块级作用域起作用.这一节我们来学习ES6新增的另一个关键字const. const 的作用 const是constant(常量)的缩写,const和 ...

  4. C++ 11 关键字

    1.auto 我现在用auto,基本是在变量定义时根据初始化表达式自动推断该变量的类型. 另外与关键字 decltype 连用,在声明或定义函数时作为函数返回值的占位符. auto不能用来声明函数的返 ...

  5. final关键字+const关键字

    final关键字 1.如果我们希望某个类不被其它的类来继承(可能因为安全考虑),可以使用final. 例题 <? final class A{} class B extends A{};//会报 ...

  6. 关键字 const

    如果关键字出现在星号左边,表示被指物是常量: 如果出现在星号右边,表示指针本身是常量: 如果出现在星号两边,表示被指物和指针都是常量. void f1(const Widget* pw); //f1和 ...

  7. C# 关键字const与readonly的区别

    尽管你写了很多年的C#的代码,但是可能当别人问到你const与readonly的区别时候,还是会小小的愣一会吧~ 笔者也是在看欧立奇版的<.Net 程序员面试宝典>的时候,才发现自己长久以 ...

  8. js-变量定义关键字const,var,let

    1.var定义的变量可以修改,如果不初始化会输出undefined,不会报错. js中最常用的关键字:基本大多数据学js时都只看到使用过var.从没相关还有其他定义 var a = 1; // var ...

  9. 如何使用C#关键字const,readonly,static

    如果有一个值不太会变化,我们经常使用const和readonly,这2者有何不同呢?有时候,我们也会在readonly之前加上关键字static,这又意味着什么呢? const ● const默认是静 ...

随机推荐

  1. CAP 5.2 版本发布通告

    前言 今天,我们很高兴宣布 CAP 发布 5.2 版本正式版,在这个版本中,我们主要致力于更好的优化使用体验以及支持新的 Transport,同时在该版本也进行了一些 bug 修复的工作. 自从 5. ...

  2. python实现模板匹配

    目录: (一)原理 (二)代码实现和几种常见的模板匹配算法 正文: (一)原理 在待检测图像上,从左到右,从上向下计算模板图像与重叠子图像的匹配度,匹配程度越大,两者相同的可能性越大. 作用有局限性, ...

  3. OAuth 2.1 带来了哪些变化

    OAuth 2.1 是 OAuth 2.0 的下一个版本, OAuth 2.1 根据最佳安全实践(BCP), 目前是第18个版本,对 OAuth 2.0 协议进行整合和精简, 移除不安全的授权流程, ...

  4. SpringMVC学习笔记---依赖配置和简单案例实现

    初识SpringMVC 实现步骤: 新建一个web项目 导入相关jar包 编写web.xml,注册DispatcherServlet 编写springmvc配置文件 接下来就是去创建对应的控制类 , ...

  5. Linux查看进程

    1.ps 有很多参数,不需要全部记住,只需要记住最有用的那些参数. unix风格的参数 比如:ps -ef查看系统上运行的所有进程 ps -l 会产生一个长格式的输出   >UID:启动这些进程 ...

  6. 【GS模型】全基因组选择之rrBLUP

    目录 1. 理论 2. 实操 2.1 rrBLUP包简介 2.2 实操 3. 补充说明 关于模型 关于交叉验证 参考资料 1. 理论 rrBLUP是基因组选择最常用的模型之一,也是间接法模型的代表.回 ...

  7. Vue.js知识点总结

    1. Vue.js简介 1.1 Vue.js简介 1.2 创建一个vue实例 2. Vue.js基础 2.1 模板语法 2.2 环境搭建 2.3 生命周期钩子

  8. TCP三次握手与Linux的TCP内核参数优化

    感谢各位技术大佬的资料分享,这里我把我理解的内容做一个整理 一:TCP的三次握手 1.TCP简述 TCP是一个面向连接的协议,在连接双方发送数据之前,首先需要建立一条连接.TCP建立连接可以简单称为: ...

  9. 小程序https启用tls1.2

    公司的web服务器是iis7,在开发微信小程序的时候,需要启用TLS1.2. 将下面的代码复制到文本,存为reg文档,双击搞定. Windows Registry Editor Version 5.0 ...

  10. 笔记Mysql(1)

    客户端的登录命令 查看版本 查看设置(数据库的基本设置信息) 查看时间 查看链接数 查看超时的关键字 创建数据库 查看已有数据库 进入数据库,查询链接到的数据库 查询数据目录 创建表 查看表