常量成员函数 (const member function), 可读取类中的数据成员,但不能修改。

1  声明

1.1  const 关键字

参数列表后,加 const 关键字,声明为常量成员函数,表明其不被允许修改类的数据成员

下面的类,以年、月、日的形式来表示日期 (注意:年月日的声明顺序)

class Date {
public:
int GetYear() const { return y_; }int GetMonth() const { return m_; }
int GetDay() const { return d_; }
void AddYear(int n); // add n years
private:
int y_, m_, d_;
};

1) 如果常量成员函数,企图修改类的数据成员,则编译器会报错

// error : attempt to change member value in const function
int Date::GetYear() const
{
return ++y_;
}

2) 如果在类外面,“定义” 常量成员函数 ( “定义” = 实现,即 implementation),则 const 关键字不可省略

// error : const missing in member function type
int Date::GetYear()
{
return y_;
}

1.2  C++ 陷阱

类中成员变量的声明顺序,决定了成员变量的初始化顺序。假设 Date 类中的构造函数为:

public:
Date() : y_(), m_(), d_() {}

此时,类中的成员函数,在类中的声明顺序 = 构造函数初始化列表顺序,故 y_, m_, d_ 都能被顺利的初始化为对应的值。

而当成员变量,在类中的声明顺序 ≠ 构造函数初始化列表顺序 时,

public:
Date() : y_(), d_(), m_(d_-) {}

根据成员变量的声明顺序,y_ 首先被初始化为 2016,然后再初始化 m_,但由于 d_ 并未被初始化,所以 m_ 的值是随机的,最后初始化 d_ 为 22

这是因为,类的成员变量在初始化时,其初始化的顺序只与声明顺序有关,而与在初始化列表中的顺序无关。

2  调用

一个常量成员函数,可以被 const 和 non-const 类对象调用; 而非常量成员函数,例如 AddYear(),则只能被 non-const 型类对象调用。

void  Date::AddYear(int n)
{
y_ += n;
}

调用函数如下:

void f(Date& d, const Date& cd)
{
int i = d.GetYear(); // OK
d.AddYear(); // OK
int j = cd.GetYear(); // OK
cd.AddYear(); // error
}

此时,const 修饰函数形参,是 “接口” 的常用指定形式, 这样 数据 可以传递给 函数 而 本身不被修改。

C++ 中的类型转换 const_cast,可以移除对象的 const 属性,具体使用为: const_cast<T>(expression)

则上例中,要使 const 型类对象,调用类的 non-const 成员函数,可修改代码如下:

void f(Date& d, const Date& cd)
{
int j = cd.GetYear(); // OK
const_cast<Date&>(cd).AddYear();
}

这种做法虽然是可以的,但它破坏了使用 const 来指定 “接口“ 的本意,并不推荐。

3  解释

this 指针 默认是指向 non-const 型类对象的 const 型,因此,不能将 this 指针和 const 型类对象绑定,即 const 类对象无法调用类的成员函数

// 默认的 this 指针,指向 non-const 类对象
Date * const this;

在成员函数声明的参数列表后加 const 后缀,表明其 this 指针指向 const 型类对象,如此, const 型类对象便可以调用常量成员函数了

// 常量成员函数中的 this 指针,指向 const 类对象
const Date * const this;

小结:

1) 类成员函数声明中的 const 后缀,表明其 this 指针指向 const 型类对象,因此该 const 类对象,可以调用常量成员函数 (const member function)

2) 一个成员函数,如果对数据成员只涉及读操作,而不进行修改操作,则尽可能声明为常量成员函数

参考资料:

<C++ Programming Language_4th> ch 16.2.9.1

<C++ Primer_5th> ch 7.1.2

<Effective C++_3rd> Item 3, item 27

<More Effective C++> Item 2

<剑指 offer> 第 7 章

C++ 之 常量成员函数的更多相关文章

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

    http://blog.csdn.net/gmstart/article/details/7046140 在C++的类定义里面,可以看到类似下面的定义: 01 class List { 02 priv ...

  2. C++官方文档-常量成员函数

    #include <iostream> using namespace std; class MyClass { public: int x; static int n; const in ...

  3. C++ const常量对象、常量成员函数和常引用

    01 常量对象 如果不希望某个对象的值被改变,则定义该对象的时候可以在前面加const关键字 class CTest { public: void SetValue() {} private: int ...

  4. C++中常量成员函数的含义

    C++中常量成员函数的含义 本文内容来源:<C++必知必会> 使用常量成员函数可以改变对象的逻辑状态,虽然对象的物理状态没有发生改变.考虑如下代码,它定义了一个类X: class X{ p ...

  5. 常量成员函数的注意事项 & mutable的使用场景

    mutable的使用场景: 可以在一个const的对象里面,解除对部分字段的const限制.也可以用在const成员函数里面. 对于const与否,一般会调用不同版本的函数: 而对于二元操作符,如果用 ...

  6. C++ 必知必会:条款16 指向成员函数的指针并非指针

    这一点与指向成员的指针类似,其实现可能更加复杂,因为成员函数同时还存在虚拟函数,需要动态绑定执行动作.当然这种属性是属于函数本身的,此处表达的是指针不涉及函数的属性问题. 1: class shape ...

  7. c++ 学习之const专题之const成员函数

    一些成员函数改变对象,一些成员函数不改变对象. 例如: int Point::GetY() { return yVal; } 这个函数被调用时,不改变Point对象,而下面的函数改变Point对象: ...

  8. C++ Const成员函数

    一些成员函数改变对象,一些成员函数不改变对象. 例如:  int Point::GetY() { return yVal; }  这个函数被调用时,不改变Point对象,而下面的函数改变Point对象 ...

  9. 类 this指针 const成员函数

    C++ Primer 第07章 类 7.1.2 ​Sales_data类的定义如下: #ifndef SALES_DATA_H #define SALES_DATA_H #include <st ...

随机推荐

  1. 轻量级的移动 webapp 框架Jingle

    一大早爬起来,发现这样的一个东东,国产,感觉实用性很强,试着用用. 1.28补记: 试着用jingle做了一个网站的移动版,感觉如果在布局上要求不高的话 - 目前支持的布局只有list,还是挺不错,做 ...

  2. Python 3.X 实现定时器 Timer,制作抽象的Timer定时器基类

    Python 在不依赖第三方库的前提下,对于定时器的实现并不是很完美,但是这不意味着我们无法实现. 阅读了网上的一些资料,得出一些结论,顺手写了一个基类的定时器(Python3) BaseTimer: ...

  3. mysql创建数据库指定编码

    GBK: create database test2 DEFAULT CHARACTER SET gbk COLLATE gbk_chinese_ci; UTF8: CREATE DATABASE ` ...

  4. LINUX重启MYSQL的命令

    LINUX重启MYSQL的命令 标签: mysqllinuxservice脚本web服务server 2010-06-25 10:21 62152人阅读 评论(0) 收藏 举报  分类: Linux( ...

  5. webpack打包

    (1) 首先生成一个package.json文件 进入项目文件的根目录执行npm init 在根目录中生成一个package.json文件 (2)全局安装webpack  执行npm install ...

  6. CSS3选择器(一)

    E[att^='val'] 选择属性值以val开头的任何字符 E[att$='val'] 选择属性值以val结尾的任何字符 E[att*='val'] 选择属性值包含val的任何字符 :root HT ...

  7. 解决SharePoint 2013 designer workflow 在发布的报错“负载平衡没有设置”The workflow files were saved but cannot be run.

    原因是app management service没有设置好,在管理中心把他删掉,重新建一个就可以了 Provision App Management Service In SharePoint 20 ...

  8. SharePoint Tricks - Survey

    1. SharePoint 2010中,在Survey的问题框中输入HTML代码可以用于插入图片或者链接,具体方法为: 1.1 在问题框中输入html, 1.2 在New Form和Edit Form ...

  9. IOS MenuController的部分操作

    这里我们要实现的将是选择按钮的自定义 综合上一节的随笔,这里给出效果图. ViewController.m // // ViewController.m // CX-MenuController // ...

  10. Swift学习--闭包中的懒加载(四)

    class ViewController: UIViewController { //格式:定义变量时前使用lazy来修饰变量,后面通过等到赋值一个闭包 // 注意点:1.必须是用var 2.闭包后面 ...