当前位置: 首页 > news >正文

C++中的const成员函数(函数声明后加const,或称常量成员函数)用法详解

  http://blog.csdn.net/gmstart/article/details/7046140

在C++的类定义里面,可以看到类似下面的定义:

01class List {
02private:
03     Node * p_head;
04     int length;
05     ……
06Public:
07     int GetLength () const;
08     bool GetNodeInfo(const int index,Node & buffer) const {…… }
09     bool DeleteNode(const int index);
10     …………
11}

可以看到,在GetLength和GetNodeInfo两个成员函数的参数列表后面出现了一个const。这个const指明了这个函数不会修改该类的任何成员数据的值,称为常量成员函数。
对于const函数的外部定义,也不能忘记书写const限定符,如下面给出GetLength函数(指返回链表的长度)的定义:

1int List::GetLength() const //这里依然不能忘记const
2{
3     Return length;
4}

如果在const成员函数的定义中出现了任何修改对象成员数据的现象,都会在编译时被检查出来,如:

1int List::GetLength() const
2{
3     Return length++; //错误!
4}

const成员函数存在的意义在于它能被const常对象调用。我们都知道,在定义一个对象或者一个变量时,如果在类型前加一个const,如const int x;,则表示定义的量为一个常量,它的值不能被修改。但是创建的对象却可以调用成员函数,调用的成员函数很有可能改变对象的值,比如下面这段程序:

1const List myList;
2myList.DeleteNode(3); //错误,DeleteLength是非const成员函数

显然调用DeleteNode这个成员函数删除一个链表结点后,很有可能改变对象中length(链表长度)这个值,这不符合const对象的规定。但是,如果不允许const对象调用任何成员函数又是非常不合理的。于是,我们把那些肯定不会修改对象的各个属性值的成员函数加上const说明符,这样,在编译时,编译器将对这些const成员函数进行检查,如果确实没有修改对象值的行为,则检验通过。以后,如果一个const常对象调用这些const成员函数的时候,编译器将会允许。比如:

1const List myList;
2myList.GetLength(); //正确,GetLength是const常函数,它返回链表长度,的确没有改变
3//属性值的行为,被检验通过

你可能会问,为什么不在一个const常对象调用成员函数的时候再进行检查呢?如果被调用的函数会改变对象的属性值,则立即打住就是了。这样就不用麻烦地在成员函数后面加const限定符了。然而,这无疑会大大增加编译时间。考虑下面这段代码:

1const List MyList;
2MyList.GetLength();
3……
4MyList.GetLength();
5……

这段代码中,GetLength被调用了两次,但是编译时却也要检查两次,倘使一个成员函数被调用多次,那么他将在每次调用的时候都会被检查。这显然大大不利。而如果在定义类的时候加上const限定符对常函数加以标记,那么编译器只是检查一次就好,在const对象调用成员函数时,const函数将会被直接放行。所以,C++采取了const限定符描述常函数方案而摈弃了后者。所以,即使一个函数没有修改对象值的行为,如果没有加上const限定符说明是常函数,那么const对象依然不能调用它。
然而,有些时候,我们却必须要让const函数具有修改某个成员数据值的能力。比如一些内部的状态量,对外部用户无所谓,但是对整个对象的运行却大有用处,如支持缓存的技术。遇到这种问题,我们可以把一个成员数据定义为mutable(多变的),它表示这个成员变量可以被const成员函数修改却不违法。比如下面定义了一个is_valid类成员:

01class List
02{
03private:
04     ……
05     mutable bool is_valid;
06     ……
07public:
08      bool CheckList() const
09     {
10          if(length >= 1) then return is_valid =true;
11          else return is_valid = false//正确!
12      };

这样,即使像CheckList这样的const成员函数修改它也是合法的。
但需要注意的时,不可滥用mutabe描述符,如果在某个类中只有少数一部分是被允许const常量函数修改的,使用mutable是再合适不过的。如果大部分数据都定义为mutable,那么最好将这些需要修改的数据放入另一个独立的对象里,并间接地访问它。

相关文章:

  • 孩子做错事不认错怎么办
  • iOS app被审核拒绝后如何打开解决方案中心的记录
  • Tiny4412裸机程序,按键检测
  • 带给你设计灵感的30个超棒的暗色系网站设计
  • Linux内核中锁机制之内存屏障、读写自旋锁及顺序锁
  • Web Service概述
  • ORACLE PL/SQL编程之 触发器
  • Android开发历程_9(Frame Animation的使用)
  • HTML5与XML的区别
  • 《JavaScript高级程序设计》笔记
  • cocos2d-lua .csb文件动画播放
  • 统计程序总距离
  • Ubuntu批量修改文件后缀名
  • 如何更改silverlight datagrid header的背景
  • 关于使用AJAX获取数据时,由于IE缓存而导致数据不更新,串数据的问题!
  • [微信小程序] 使用ES6特性Class后出现编译异常
  • 【399天】跃迁之路——程序员高效学习方法论探索系列(实验阶段156-2018.03.11)...
  • 【干货分享】SpringCloud微服务架构分布式组件如何共享session对象
  • 2018一半小结一波
  • HTML-表单
  • IOS评论框不贴底(ios12新bug)
  • JavaScript设计模式之工厂模式
  • KMP算法及优化
  • Laravel 菜鸟晋级之路
  • Netty 框架总结「ChannelHandler 及 EventLoop」
  • python大佬养成计划----difflib模块
  • Spring框架之我见(三)——IOC、AOP
  • Transformer-XL: Unleashing the Potential of Attention Models
  • 第三十一到第三十三天:我是精明的小卖家(一)
  • 动态规划入门(以爬楼梯为例)
  • 排序算法学习笔记
  • 前端技术周刊 2018-12-10:前端自动化测试
  • 前端自动化解决方案
  • 设计模式 开闭原则
  • 使用parted解决大于2T的磁盘分区
  • 思考 CSS 架构
  • 算法-插入排序
  • 通信类
  • 系统认识JavaScript正则表达式
  • const的用法,特别是用在函数前面与后面的区别
  • PostgreSQL之连接数修改
  • Spring Batch JSON 支持
  • 正则表达式-基础知识Review
  • ​​​​​​​sokit v1.3抓手机应用socket数据包: Socket是传输控制层协议,WebSocket是应用层协议。
  • ​马来语翻译中文去哪比较好?
  • (C#)Windows Shell 外壳编程系列9 - QueryInfo 扩展提示
  • (ZT)一个美国文科博士的YardLife
  • (二)c52学习之旅-简单了解单片机
  • (二)PySpark3:SparkSQL编程
  • (非本人原创)我们工作到底是为了什么?​——HP大中华区总裁孙振耀退休感言(r4笔记第60天)...
  • (离散数学)逻辑连接词
  • (力扣)循环队列的实现与详解(C语言)
  • (强烈推荐)移动端音视频从零到上手(上)
  • (强烈推荐)移动端音视频从零到上手(下)
  • (转)Android中使用ormlite实现持久化(一)--HelloOrmLite