工作已经进入到了11年的工龄了。在我这个年龄大部分人都去做管理岗位了。

对于我来说, 还是忠于编程,编程就是我的兴趣爱好。干一行就爱一行。

开始学习C++的基础知识。在看《C++程序设计语言》的时候,看到引用这章节的介绍时,里面有这么一段代码:

template<class T>
class vector {T* elem;// ...
public:T& operator[](int i) { return elem[i]; }const T& operator[](int i) const { return elem[i]; }void push_back(const T& a);//...
};void f(const vector<double>& v)
{double d1 = v[1];v[2] = 7;    //set 7 to v.operator[](2) indirect doublev.push_back(d1);
}

在f函数里面, v[2]被设置成了值7,这里就很困惑。vector不是被设定成了常量吗?怎么可以改变引用对象的值呢?颠覆了我的三观。

看来需要重新复习常量的基础知识了。

一:const修饰成员变量

从基础介绍中了解:const大致意思是“我承诺不改变这个值”。主要用于说明接口,这样在把变量传入函数时就不必担心变量会在函数内被改变了。编译器负责确认并执行const的承诺。一旦我们把某物声明成const,就确保它的值在其作用域内不会发生改变。

对于指针这个类型定义的常量来看。我们要了解指针的一些信息。一个指针牵扯到两个对象,指针本身以及指针所指的对象。所以存在两种指针类型的常量。

1,在指针的声明语句中“前置”const关键字将令所指的对象而非指针本身成为常量。

2,在指针的声明语句中“后置”const关键字将令指针本身成为常量。

如下:

#include<iostream>
using namespace std;
int main(int arc, char **argv){int a1=3;   ///non-const dataconst int a2=a1;    ///const dataint * a3 = &a1;   ///non-const data,non-const pointerconst int * a4 = &a1;   ///const data,non-const pointerint * const a5 = &a1;   ///non-const data,const pointerint const * const a6 = &a1;   ///const data,const pointerconst int * const a7 = &a1;   ///const data,const pointerreturn 0;
}

这是一些有关常用指针的sample。声明运算符 *const的作用是令指针本身成为常量。C++允许把非const变量的地址赋给指向常量的指针,不允许把常量的地址赋给某个不受限的指针。

介绍到这里,我们返回到刚开始写的常量引用是怎么回事?那么还是需要首先理解引用的本质。

引用是一种C++的语言机制,和指针类似,作为对象的别名存放对象的机器地址。与指针相比,引用不会带来额外的开销。

二者之间的区别:

  • 访问引用与访问对象本身从语法形式上看是一样的。
  • 引用所引的永远是一开始初始化的那个对象
  • 不存在“空引用”,我们可以认为引用一定对应着某个对象

引用最重要的用途是作为函数的实参或者返回值。

存在三种形式的引用:

左值引用(lvalue reference):引用那些我们希望改变值的对象。

const引用(const reference):引用那些我们不希望改变值的对象(比如常量)

右值引用(rvalue reference):所引用对象的值在我们使用之后就无须保留了(比如临时变量)

这三种形式统称为引用,其中前两种形式都是左值引用

引用的实现方式类似于常量指针,每次使用引用实际上是对该指针执行解引用操作。(这种只是辅助理解,引用不是对象,指针式一种对象)。

回到了引发这边博文的核心问题点,const类型的引用。《C++程序设计语言》【第四版】中的第165中有这么一段话:

const T& 的初始值不一定非得是左值,甚至可以不是T类型的。此时:

  • 首先,如果必要的话先执行目标为T的隐式类型转换
  • 然后,所得的值置于一个T类型的临时变量中
  • 最后,把这个临时变量作为初始值

事咧:

double & d1 = 1;              //错误:此处需要左值

const double& cdr {1};   //OK

const的这条语句的初始化过程可以理解为:

double temp = double{1};      //首先用给定的值创建一个临时变量

const double& cdr {temp};    //然后用这个临时变量作为cdr的初始值

用于存放引用初始值的临时变量的生命周期从它创建之处开始,到它的引用作用域结束为止。

我写了一段测试代码如下:

#include <iostream>using namespace std;
void display(int const &ref) {ref = 7;  //对常量引用ref进行重新赋值cout << ref << '\n';
}int main() {int i = 1;display(i);int const anotheri = 2;display(anotheri);display(2);display(1 + 2);display(static_cast<int>(3.14159));
}

编译结果如下:

medeadeMacBook-Pro:C++ medea$ g++ const_test.c -o const_test
clang: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated [-Wdeprecated]
const_test.c:5:9: error: cannot assign to variable 'ref' with const-qualified type 'const int &'ref = 7;~~~ ^
const_test.c:4:25: note: variable 'ref' declared const here
void display(int const &ref) {~~~~~~~~~~~^~~
1 error generated.

可以看到常量引用是不能赋值的。那么回到最初代码进行再次分析:

    T& operator[](int i) { return elem[i]; }const T& operator[](int i) const { return elem[i]; }

以上可以看到其实对操作符[],有两个重载函数。调用的代码如下:

void f(const vector<double>& v)
{double d1 = v[1];v[2] = 7;    //set 7 to v.operator[](2) indirect doublev.push_back(d1);
}

对于v[2] = 7,首先执行的是是操作符号[]。那么到底匹配那个重载函数呢?我们用事实来证明,参照下面的代码:

#include <iostream>template<class T>
class vector {T* elem;// ...
public:T& operator[](int i) { return elem[i]; }const T& operator[](int i) const { return elem[i]; }};void f(const vector<double>& v)
{double d1 = v[1];v[2] = 7;    //set 7 to v.operator[](2) indirect double
}int main(int argc, char **argv)
{vector<double> test;f(test);return 0;
}

编译结果如下:

medeadeMacBook-Pro:C++ medea$ g++ const_vector.c -o const_vector
clang: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated [-Wdeprecated]
const_vector.c:16:10: error: cannot assign to return value because function 'operator[]' returns a const valuev[2] = 7;    //set 7 to v.operator[](2) indirect double~~~~ ^
const_vector.c:9:11: note: function 'operator[]' which returns const-qualified type 'const double &' declared hereconst T& operator[](int i) const { return elem[i]; }^~
1 error generated.

也是编译不过。 难道不能重载。

把const T& operator[](int i) const { return elem[i]; }注释掉后,继续编译结果如下:

medeadeMacBook-Pro:C++ medea$ g++ const_vector.c -o const_vector
clang: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated [-Wdeprecated]
const_vector.c:15:18: error: no viable overloaded operator[] for type 'const vector<double>'double d1 = v[1];~^~
const_vector.c:8:8: note: candidate function not viable: 'this' argument has type 'const vector<double>', but method is not marked constT& operator[](int i) { return elem[i]; }^
const_vector.c:16:6: error: no viable overloaded operator[] for type 'const vector<double>'v[2] = 7;    //set 7 to v.operator[](2) indirect double~^~
const_vector.c:8:8: note: candidate function not viable: 'this' argument has type 'const vector<double>', but method is not marked constT& operator[](int i) { return elem[i]; }^
2 errors generated.

通过上面两次实验,可以知道。首先:

1,main函数中调用f函数,将test对象复制给常量引用const vector<double>& v。

2,由于形参是常量引用,所以调用的函数也必须是const类型。当调用操作符[]的时候,需要匹配const T& operator[](int i) const 函数。

综上所诉,这里应该是书本上写错了。至少是翻译的中文版本是写错了。英文版本有时间在去看看。

到这里const引用的语言机制(编译器行为)已经比较清晰。但是又引发出来了一个新的问题:

引用类似于常量指针,那么const引用从字面上面理解应该代表的是引用住对象的不变性。如果按照上面的语言机制,const引用是可以写入值的,使用一个临时变量保存备份,有什么特殊意义?

这个问题需要答案,期待阅读这篇文章的大牛们帮忙解惑。

C++ Const 初步总结(《C++程序设计语言》读后感)相关推荐

  1. 【C语言学习笔记】《C程序设计语言》读后感

    Warning: 为了避免非零基础人群感到身体不适.头晕恶心.易怒及粗口,请不要查看以下内容. 文章目录 前言 读书感悟 总结 前言 截至目前为止,我已经"抄"完了10篇<C ...

  2. C程序设计语言(第2版)

    C程序设计语言(第2版) 这儿有一篇写的很好的读后感:http://www.cnblogs.com/xkfz007/articles/2566424.html 第1章 导言 1. 单词计数 #incl ...

  3. [渝粤教育] 西南科技大学 程序设计语言VB 在线考试复习资料(1)

    程序设计语言VB--在线考试复习资料 一.单选题 1.列表项选择后得到的选中索引是指(). A.Value B.ListValue C.Index D.ListIndex 2.为了隐藏一个窗体,所使用 ...

  4. C语言 const 和 define 区别 - C语言零基础入门教程

    目录 一.const 使用 1.const 修饰变量 2.const 修饰指针 3.const 修饰在函数名前面 4.const 修饰在函数名后面 5.const 修饰函数参数 二.define 使用 ...

  5. C++程序设计语言编程风格演变史

    程序代码也有风格,这算不得什么新鲜事.早在20世纪80年代,C语言程序员就必须在K&R风格和ANSI风格之间择善而从.但平心而论,我确实没有见过哪一种语言能像C++这样,在代码风格方面表现得如 ...

  6. c语言程序优化设计,C程序设计语言的教学策略优化设计

    摘要:本文围绕提高C语言课堂教学的教学质量,依据教学内容的属性与特点,融合任课教师的教学经验与智慧,通过选择恰当的教学方法,采用合理的教学手段设计了一种教学优化策略,强化了教学方案设计的科学性,保证了 ...

  7. 《C程序设计》读后感

    <C程序设计>读后感 网上很多人评价这书不高,其实从内心里讲,是这本书带领我入门的.我说的是谭浩强先生的书. 这本书讲得很细,而且知识的衔接也做得很好.我以这本书为重点,再以其它的C语言教 ...

  8. 数学模型转化为计算机语言,程序设计语言类课程教学选题方法探讨

    <程序设计语言类课程教学选题方法探讨>由会员分享,可在线阅读,更多相关<程序设计语言类课程教学选题方法探讨(6页珍藏版)>请在人人文库网上搜索. 1.程序设计语言类课程教学选题 ...

  9. Ada 程序设计语言(The Ada Programming Language)[第一集]

    Ada 程序设计语言(The Ada Programming Language)[第一集]- - 版权(Copyright) <Ada 程序设计语言>的版权隶属于网站 VenusIC,允许 ...

  10. C 程序设计语言——第四章练习题

    C 程序设计语言第二版--第四章练习题 1. Write the function strindex(s,t) which returns the position of the rightmost ...

最新文章

  1. 一文告诉你,NIPS 2017有多火爆 | 附PPT、视频、代码大总结
  2. 第 3 章 镜像 - 010 - base 镜像
  3. 微软独立虚拟机Hyper-V Server 2008
  4. delete if only one note header
  5. conda 换成清华的源_conda/pip 使用国内镜像安装第三方库
  6. C# 将已有程序封装为DLL文件,供其他程序调用
  7. [2018.10.25 T3] 旅程
  8. java 虚拟机常用启动参数
  9. 计算机恢复出厂设置xp,电脑xp一键恢复出厂设置
  10. 针对百度的常规网页优化策略
  11. snipaste 方便快捷截图工具
  12. 倍福--232/485通信
  13. 3G终端变局:安卓崛起 联通高调摆脱苹果
  14. 正电荷/内质网靶向性/蓝色/mCy-ER/绿色/开关型/CySeN花菁染料近红外荧光探针的制备
  15. 应用Druid监控SQL语句的执行情况
  16. 太白非技术类随笔(猛击这里!!!)
  17. chrome浏览器缓存视频_如何录制您的Chrome浏览器的视频
  18. 高德地图获取可视区域内四角坐标(东北,东南,西南,西北)
  19. cpmp(compulsory)
  20. 如何编辑ofd格式文档?

热门文章

  1. 信号卷积和图像卷积滤波
  2. todd li 保留_用Todd Motto揭开JavaScript神秘面纱
  3. 精灵骑士二觉_精灵骑士二觉版本小百科,先睹为快
  4. Aurora使用教程 第一讲
  5. JAVA解题【We Are A Team】
  6. 2022-09-29 C++并发编程(二十八)
  7. kangle安装php7.0_搭建Kangle+EasyPanel对接SWAP IDC虚拟主机自助开通完整教程
  8. 滴滴6月或发布造车计划;头部App上线一键关闭 “个性化推荐 ”​;下载捆绑,“高速下载”竟为元凶 | EA周报...
  9. “Google Play In-app Billing API version is less than 3”的解决方法
  10. java实现mysql拦截_在mybatis执行SQL语句之前进行拦击处理实例