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

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

01 class List {
02 private:
03      Node * p_head;
04      int length;
05      ……
06 Public:
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函数(指返回链表的长度)的定义:

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

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

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

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

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

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

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

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

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

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

01 class List
02 {
03 private:
04      ……
05      mutable bool is_valid;
06      ……
07 public:
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,那么最好将这些需要修改的数据放入另一个独立的对象里,并间接地访问它。

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

  1. C++ 成员函数前和函数后加const修饰符区别

    博客转载自: https://www.iteblog.com/archives/214.html 分析以下一段程序,阐述成员函数后缀const 和 成员函数前const 的作用 #include< ...

  2. [Reprint]C++函数前和函数后加const修饰符区别

    c++中关于const的用法有很多,const既可以修饰变量,也可以函数,不同的环境下,是有不同的含义.今天来讲讲const加在函数前和函数后面的区别.比如: 01 #include<iostr ...

  3. C++函数前和函数后加const修饰符区别

    class Test(){ public: Test(){} const int foo(int a); const int foo(int a) const; }; 一.概念 当const在函数名前 ...

  4. delphi中Application.MessageBox函数用法详解

    delphi中Application.MessageBox函数用法详解 Application.MessageBox是TApplication的成员函数,声明如下:functionTApplicati ...

  5. SQL中CONVERT()函数用法详解

    SQL中CONVERT函数格式: CONVERT(data_type,expression[,style]) 参数说明: expression 是任何有效的 Microsoft® SQL Server ...

  6. php中setcookie函数用法详解(转)

    php中setcookie函数用法详解:        php手册中对setcookie函数讲解的不是很清楚,下面是我做的一些整理,欢迎提出意见.        语法:        bool set ...

  7. C++中const用法详解

    本文主要内容来自CSDN论坛: http://bbs.csdn.net/topics/310007610 我做了下面几点补充. 补充: 1. 用const声明全局变量时, 该变量仅在本文件内可见, 类 ...

  8. C语言对文件的操作函数用法详解2

    fopen(打开文件) 相关函数 open,fclose 表头文件 #include<stdio.h> 定义函数 FILE * fopen(const char * path,const  ...

  9. Delphi Format函数功能及用法详解

    DELPHI中Format函数功能及用法详解 DELPHI中Format函数功能及用法详解function Format(const Format: string; const Args: array ...

随机推荐

  1. 【算法】解析IEEE 754 标准

    目录结构: contents structure [-] 浮点数的存储过程 次正规数(Denormalized Number) 零(zero) 非数值(NaN) 无穷大(infinity) 除数为0. ...

  2. 企业级镜像仓库Harbor

    介绍: Habor是由VMWare公司开源的容器镜像仓库.事实上,Habor是在Docker Registry上进行了相应的企业级扩展,从而获得了更加广泛的应用,这些新的企业级特性包括:管理用户界面, ...

  3. FFmpeg libavutil主要功能概述

    [时间:2017-08] [状态:Open] [关键词:ffmpeg,avutil,avrational,avlog,avbuffer,avoptoin] 0 引言 FFmpeg使用很久了,一直没有认 ...

  4. 【Java】设计模型-五种单例模型

    一. 什么是单例模式 只需要某个类同时保留一个对象,不希望有更多对象,此时,我们则应考虑单例模式的设计. 单例模式的主要作用是保证在Java程序中,某个类只有一个实例存在. 单例模式有很多好处,它能够 ...

  5. Spring-boot之 swagger2

    Swagger是一个简单但功能强大的API表达工具. 结合springboot 配置起来很简单,附上教程 :https://www.xncoding.com/2017/07/08/spring/sb- ...

  6. Linux系统时间同步方法小结

    在Windwos中,系统时间的设置很简单,界面操作,通俗易懂,而且设置后,重启,关机都没关系.系统时间会自动保存在BIOS时钟里面,启动计算机的时候,系统会自动在BIOS里面取硬件时间,以保证时间的不 ...

  7. array_walk 与 array_map的 区别

    1.array_walk是用于用户自定义的函数,所以想用array_walk($aIds, "trim");去掉数据元素中的空格是达不到目的的只能用array_walk($aIds ...

  8. scala 隐式详解(implicit关键字)

    掌握implicit的用法是阅读spark源码的基础,也是学习scala其它的开源框架的关键,implicit 可分为: 隐式参数 隐式转换类型 隐式调用函数 1.隐式参数 当我们在定义方法时,可以把 ...

  9. python数据分析及展示(三)

    一.Pandas库入门 1. Pandas库的介绍 http://pandas.pydata.org Pandas是Python第三方库,提供高性能易用数据类型和分析工具 import pandas ...

  10. 解决FAT32格式U盘安装win10时0x8007000D错误

    问题由来 我一直使用U盘,UltraISO软碟通和msdn原版镜像来装系统.最近在把Win10 1709升级为1803时遇到了问题.同样也是使用UltraISO刻录镜像到U盘的方法安装的,这次从U盘启 ...