在之前随笔《C++中const使用要点(一)》中简单叙述了const int*、int* const和const int* const的区别,记住三句话就能在实际运用时用对,但是看书时发现了指针常量、常量指针这些名词,发现明白这些概念对阅读文章时还是比较重要的。

关键:const和指针结合时代码从右往左看

1、常量指针(const pointer)

概念:常量是形容词,也就是说常量指针是一个指针,用const修饰的指针。

按照代码从右往左(概念名词从左往右)的阅读顺序,不妨试着写一下。

Step1: i; // 变量名

Step2: const i;  // 第一个名词是const,写在i的左边

Step3: int* const i;  // 第二个名词是pointer(*),以具体类型int*为例,写在const i的左边
2、指向常量的指针(pointer to const),一般简称为指针常量(这种翻译很不好,容易混淆)

概念:指向常量是形容词,指向常量的指针也是一个指针,但是本身不是const,指向的对象是const

继续来试着写一下。

Step1: i; // 变量名

Step2: * i; // 第一个名词是pointer,*写在i的左边

Step3: const int* i; // 第二个名词是const,以const int为例,写在*的左边。

int const* i;  // 这种写法也对,可以理解为先在* i左边写个const,表示指向的是常量,再在const* i左边写上这个常量的具体类型

3、指向常量的常量指针

同样的写法,先在变量名的左边写上const,再在const左边写上*,之后左边是const int或int const都行

  1. int i = 0, j = 1;
  2. // 常量指针, p1是const, p1指向的是int(而不是const int)
  3. int* const p1 = &i; // 必须初始化, 因为指向的对象不能更改
  4. // p1 = &j; // 这句想把j的地址赋值给p1, 而p1又是const
  5. *p1 = 2; // 指向的是int, 没有const修饰, 可以更改
  6.  
  7. // 指向常量的指针, p2不是const, p2指向的是const int
  8. const int* p2; // 可以不初始化(悬挂指针), 反正以后可以选择指向的对象
  9. p2 = &j; p2 = &i; // 随意修改指向的对象
  10. //*p2 = 1; // 指向的是const int, 不可以更改
  11.  
  12. // 指向常量的常量指针, p3是const, p3指向的也是const
  13. const int* const p3 = &i;
  14. // p3 = &j; // 错误, 因为p3是const
  15. // *p3 = 3; // 错误, 因为p3指向的也是const

为了代码的易读性,使用typedef把指针简化比较常见

以前最显著的用法就是把函数指针(指向函数的指针)给简化。

函数指针的代码阅读方法是从里到外

int (*Func)(int, int);

这句代码的阅读方式:

Step1: 最里面的是变量名Func,它是一个函数指针

Step2: 往左读,Func返回的是int;往右读,Func参数是2个int

复杂一点的话……

float (*(*Func)(int,int))(int);

Step1: 最里面的是变量名Func,它是一个函数指针,接受1个int参数,返回的还是个函数指针

Step2: 设返回的函数指针为Func1,即typedef float(*Func1)(int);

Step3: 这下就好读了,Func1接受1个int参数,返回float。

好吧,回归正题。用typedef要注意的一点就是不能跟C语言常用的#define等价,虽然在C++中确实是用来代替#define的。

因为typedef不是直接替换代码,而是把这段代码当成一个类型。

直接上代码说明吧

  1. typedef int* pInt;
  2. int i = 0, j = 1;
  3. // 这里把pInt就当成个暂时未知基本数据类型, 说明p1是const
  4. // 再来看看pInt的具体类型, 是个指向int的指针
  5. // 也就是说p1是指针, p1是const, 指向的是int(不是const int)
  6. const pInt p1 = &i; // 等价于pInt const或int* const
  7. // p1 = &j; // 错误
  8. *p1 = 2;
  9.  
  10. int *p2 = &i, *p3 = &j;
  11. int **pp1 = &p2, **pp2 = &p3;
  12. // pp2是个指针, 指向的是const pInt
  13. const pInt* pp3;
  14. pp3 = pp1;
  15. pp3 = pp2; // 可以随便改变指向的对象
  16. // *pp3 = p2; // 错误, pp3指向的是const类型(const pInt), 不能修改
  17. *(*pp3) = 4; // 正确, [pp3指向的const pInt]指向的是pInt(这个pInt指向的是int, 可以修改)

另外,在C++ Primer上还看到了顶层(top-level)const底层(low-level)const的概念

底层const:指向的对象不能修改(比如const int*)

顶层const:指针或变量本身不能修改(比如const int、int* const)

const int* const兼具底层和顶层性质

关键1:只有有底层const性质的指针才能转换为相同底层const资格的指针!

比如const int* const兼具底层和顶层const性质。

  1. int i = 1;
  2. const int* p1 = &i;
  3. const int* const p2 = &i;
  4. p1 = p2;
  5. // p2 = p1; // 错误, 因为p2本身不能修改

其实不知道顶层底层也能理解,就像const T能转换为T一样。(T为数据类型)

T&不能转换为const T&,T&也不能绑定const T(常见错误,在《C++中const使用要点(二)》中提过类似)的

T*不能你转换为const T*。但是指针的情况比较特殊,比如可以像下列代码一样强制转换

  1. const int* pInt1 = &i;
  2. int* pInt2 = &i;
  3. // 可以强制转换
  4. pInt2 = (int*)pInt1;
  5. pInt2 = const_cast<int*>(pInt1);

关键2:auto类型只能推测出底层const性质!

  1. auto a = &ci; // a是const int*, 底层const保留
  2. auto b = ci; // b是int, 顶层const被忽略

针对这个问题,C++ 11新增了decltype类型,可以保留顶层const。

比如上述代码第二行改为decltype(b) = ci;后b就是const int类型

结合示例说明C++中const和指针结合时怎么理解的更多相关文章

  1. C++中const和指针

    常见的理解问题: const char * * s;//表示s是指向const char * 类型的指针: char * * const s;//表示s是指向char * 类型的一个常量指针.

  2. C++中const简介及用法

    1.const简介 C++中的const关键字的用法非常灵活,而使用const将大大改善程序的健壮性,本人根据各方面查到的资料进行总结如下,期望对朋友们有所帮助. Const 是C++中常用的类型修饰 ...

  3. const与指针

    C++中const与指针 1.常指针: ; int * const pInt = &x; 其中PInt是常指针,pInt的值无法改变,但其指向的内容可以改变. 2.指向常量的指针 有两种写法: ...

  4. PHP中使用数组指针函数操作数组示例

    数组的内部指针是数组内部的组织机制,指向一个数组中的某个元素.默认是指向数组中第一个元素通过移动或改变指针的位置,可以访问数组中的任意元素.对于数组指针的控制PHP提供了以下几个内建函数可以利用. ★ ...

  5. C++中使用const修饰指针

    在本文中呢,主要讲解四个方面,即:常量数据的与否和常量指针的与否中const如何对指针进行修饰: 1.指向非常量数据的常量指针 对于一个指向非常量数据的常量指针,我们应该清楚的知道,在这我们注重的是指 ...

  6. C++中const指针用法汇总

    这里以int类型为例,进行说明,在C++中const是类型修饰符: int a; 定义一个普通的int类型变量a,可对此变量的值进行修改. const int a = 3;与 int const a ...

  7. C++中的const和指针组合

    在C++里,const修饰指针有以下三种情况 (1)指针常量:即指向常量的指针 const  int *p或者int const *p const在*前,,可以这样理解它的功能,因为const在*前, ...

  8. C++中const修饰基本数据类型、指针、引用、对象

    const修饰基本数据类型 #include <iostream> using namespace std; void main(){ const int a = 1; const cha ...

  9. c++中的const与指针

    const修饰符 使用const修饰变量时,该变量的值不可修改,因此需要初始化. 例如 const int s = 0: 此时s为值不可变的变量. 那么基于此,当const修饰指针时的情况有三种: ( ...

随机推荐

  1. percona innobackupex 遇到 connect to MySQL server as DBD::mysql module is not installed 问题

    percona innobackupex connect to MySQL server as DBD::mysql module is not installed [root@mysql softw ...

  2. 【51nod-1396】还是01串

    给定一个0-1串s,长度为n,下标从0开始,求一个位置k,满足0<=k<=n, 并且子串s[0..k - 1]中的0的个数与子串s[k..n - 1]中1的个数相等. 注意: (1) 如果 ...

  3. 一台服务器的IIS绑定多个域名

    等待十分钟: 在IIS上配置:

  4. 生产者与消费者的Java实现

    首先创建maven工程,需要引入的包: <dependencies> <dependency> <groupId>org.apache.kafka</grou ...

  5. MoreEffectiveC++Item35(效率)(条款16-24)

    条款16 谨记80-20法则 条款17 考虑使用 lazy evaluation(缓释评估) 条款18 分期摊还预期的计算成本 条款19 了解临时对象的来源 条款20 协助完成"返回值的优化 ...

  6. c# 自定义排序类(冒泡、选择、插入、希尔、快速、归并、堆排序等)

    using System; using System.Text; namespace HuaTong.General.Utility { /// <summary> /// 自定义排序类 ...

  7. HM安装和使用方法

    此文为学习JVET参考了HM的安装方法,转载自岳麓吹雪大牛的博客,膜拜. 早期的HM解决方案包含了7个工程:1. TAppCommon 2. TAppDecoder 3. TAppEncoder 4. ...

  8. d3.js(v5.7)的比例尺以及坐标轴

    直接上代码了,这里的一些函数用的是之前我自己封装的函数(包括attr的obj支持和节点数量和数据数量的自动匹配),若有不明白的,可以查看之前的博客: 页面的效果如下: 接下来继续添加坐标轴: 最终:

  9. 【译】从数学公式入手,详细了解 Animation 的 Interpolators

    我们在做动画的时候,总是避免不了会使用到 Interpolator(插值器)这个东西,比如 LinearInterpolator 等.这样做的好处是,能够让动画的变化速度符合现实世界中的物理规律,看上 ...

  10. 使用tr1的bind函数模板

    最近把公司的VS2008统一升级为SP1了,虽然还是有些跟不上时代,毕竟C++17标准都出了,但是,对于成熟的商业软件开发而言,追求更新的C++标准肯定不是正道.升级SP1的VS2008可以支持TR1 ...