zoukankan      html  css  js  c++  java
  • 结合示例说明C++中const和指针结合时怎么理解

    在之前随笔《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都行

    	int i = 0, j = 1;
    	// 常量指针, p1是const, p1指向的是int(而不是const int)
    	int* const p1 = &i;  // 必须初始化, 因为指向的对象不能更改
    	// p1 = &j; // 这句想把j的地址赋值给p1, 而p1又是const
    	*p1 = 2; // 指向的是int, 没有const修饰, 可以更改
    
    	// 指向常量的指针, p2不是const, p2指向的是const int
    	const int* p2; // 可以不初始化(悬挂指针), 反正以后可以选择指向的对象
    	p2 = &j; p2 = &i;  // 随意修改指向的对象
    	//*p2 = 1;  // 指向的是const int, 不可以更改
    
    	// 指向常量的常量指针, p3是const, p3指向的也是const
    	const int* const p3 = &i;
    	// p3 = &j; // 错误, 因为p3是const
    	// *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不是直接替换代码,而是把这段代码当成一个类型。

    直接上代码说明吧

    	typedef int* pInt;
    	int i = 0, j = 1;
    	// 这里把pInt就当成个暂时未知基本数据类型, 说明p1是const
    	// 再来看看pInt的具体类型, 是个指向int的指针
    	// 也就是说p1是指针, p1是const, 指向的是int(不是const int)
    	const pInt p1 = &i;  // 等价于pInt const或int* const
    	// p1 = &j; // 错误
    	*p1 = 2;
    
    	int *p2 = &i, *p3 = &j;
    	int **pp1 = &p2, **pp2 = &p3;
    	// pp2是个指针, 指向的是const pInt
    	const pInt* pp3;
    	pp3 = pp1;
    	pp3 = pp2; // 可以随便改变指向的对象
    	// *pp3 = p2; // 错误, pp3指向的是const类型(const pInt), 不能修改
    	*(*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性质。

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

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

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

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

    	const int* pInt1 = &i;
    	int* pInt2 = &i;
    	// 可以强制转换
    	pInt2 = (int*)pInt1;
    	pInt2 = const_cast<int*>(pInt1);

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

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

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

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

  • 相关阅读:
    [c++]基类对象作为函数參数(赋值兼容规则)
    easyui datagird 总计栏
    openssl之BIO系列之25---结束语
    具体解释Hibernate中的二级缓存
    记真实自己,炫精彩人生---《爱记》app使用体验
    设置-安全-手机加密功能解说
    Linux下Redis安装
    解题报告 之 HDU5317 RGCDQ
    FireFox所支持的全部标签(持续更新ing)
    本书已出版&lt;拨云见日:基于android的内核与系统架构源代码分析 &gt;
  • 原文地址:https://www.cnblogs.com/Harley-Quinn/p/5366210.html
Copyright © 2011-2022 走看看