C++ Const 初步总结(《C++程序设计语言》读后感)
工作已经进入到了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++程序设计语言》读后感)相关推荐
- 【C语言学习笔记】《C程序设计语言》读后感
Warning: 为了避免非零基础人群感到身体不适.头晕恶心.易怒及粗口,请不要查看以下内容. 文章目录 前言 读书感悟 总结 前言 截至目前为止,我已经"抄"完了10篇<C ...
- C程序设计语言(第2版)
C程序设计语言(第2版) 这儿有一篇写的很好的读后感:http://www.cnblogs.com/xkfz007/articles/2566424.html 第1章 导言 1. 单词计数 #incl ...
- [渝粤教育] 西南科技大学 程序设计语言VB 在线考试复习资料(1)
程序设计语言VB--在线考试复习资料 一.单选题 1.列表项选择后得到的选中索引是指(). A.Value B.ListValue C.Index D.ListIndex 2.为了隐藏一个窗体,所使用 ...
- C语言 const 和 define 区别 - C语言零基础入门教程
目录 一.const 使用 1.const 修饰变量 2.const 修饰指针 3.const 修饰在函数名前面 4.const 修饰在函数名后面 5.const 修饰函数参数 二.define 使用 ...
- C++程序设计语言编程风格演变史
程序代码也有风格,这算不得什么新鲜事.早在20世纪80年代,C语言程序员就必须在K&R风格和ANSI风格之间择善而从.但平心而论,我确实没有见过哪一种语言能像C++这样,在代码风格方面表现得如 ...
- c语言程序优化设计,C程序设计语言的教学策略优化设计
摘要:本文围绕提高C语言课堂教学的教学质量,依据教学内容的属性与特点,融合任课教师的教学经验与智慧,通过选择恰当的教学方法,采用合理的教学手段设计了一种教学优化策略,强化了教学方案设计的科学性,保证了 ...
- 《C程序设计》读后感
<C程序设计>读后感 网上很多人评价这书不高,其实从内心里讲,是这本书带领我入门的.我说的是谭浩强先生的书. 这本书讲得很细,而且知识的衔接也做得很好.我以这本书为重点,再以其它的C语言教 ...
- 数学模型转化为计算机语言,程序设计语言类课程教学选题方法探讨
<程序设计语言类课程教学选题方法探讨>由会员分享,可在线阅读,更多相关<程序设计语言类课程教学选题方法探讨(6页珍藏版)>请在人人文库网上搜索. 1.程序设计语言类课程教学选题 ...
- Ada 程序设计语言(The Ada Programming Language)[第一集]
Ada 程序设计语言(The Ada Programming Language)[第一集]- - 版权(Copyright) <Ada 程序设计语言>的版权隶属于网站 VenusIC,允许 ...
- C 程序设计语言——第四章练习题
C 程序设计语言第二版--第四章练习题 1. Write the function strindex(s,t) which returns the position of the rightmost ...
最新文章
- 一文告诉你,NIPS 2017有多火爆 | 附PPT、视频、代码大总结
- 第 3 章 镜像 - 010 - base 镜像
- 微软独立虚拟机Hyper-V Server 2008
- delete if only one note header
- conda 换成清华的源_conda/pip 使用国内镜像安装第三方库
- C# 将已有程序封装为DLL文件,供其他程序调用
- [2018.10.25 T3] 旅程
- java 虚拟机常用启动参数
- 计算机恢复出厂设置xp,电脑xp一键恢复出厂设置
- 针对百度的常规网页优化策略
- snipaste 方便快捷截图工具
- 倍福--232/485通信
- 3G终端变局:安卓崛起 联通高调摆脱苹果
- 正电荷/内质网靶向性/蓝色/mCy-ER/绿色/开关型/CySeN花菁染料近红外荧光探针的制备
- 应用Druid监控SQL语句的执行情况
- 太白非技术类随笔(猛击这里!!!)
- chrome浏览器缓存视频_如何录制您的Chrome浏览器的视频
- 高德地图获取可视区域内四角坐标(东北,东南,西南,西北)
- cpmp(compulsory)
- 如何编辑ofd格式文档?
热门文章
- 信号卷积和图像卷积滤波
- todd li 保留_用Todd Motto揭开JavaScript神秘面纱
- 精灵骑士二觉_精灵骑士二觉版本小百科,先睹为快
- Aurora使用教程 第一讲
- JAVA解题【We Are A Team】
- 2022-09-29 C++并发编程(二十八)
- kangle安装php7.0_搭建Kangle+EasyPanel对接SWAP IDC虚拟主机自助开通完整教程
- 滴滴6月或发布造车计划;头部App上线一键关闭 “个性化推荐 ”​;下载捆绑,“高速下载”竟为元凶 | EA周报...
- “Google Play In-app Billing API version is less than 3”的解决方法
- java实现mysql拦截_在mybatis执行SQL语句之前进行拦击处理实例