C++ 之 常量成员函数
常量成员函数 (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++ 之 常量成员函数的更多相关文章
- C++中的const成员函数(函数声明后加const,或称常量成员函数)用法详解
http://blog.csdn.net/gmstart/article/details/7046140 在C++的类定义里面,可以看到类似下面的定义: 01 class List { 02 priv ...
- C++官方文档-常量成员函数
#include <iostream> using namespace std; class MyClass { public: int x; static int n; const in ...
- C++ const常量对象、常量成员函数和常引用
01 常量对象 如果不希望某个对象的值被改变,则定义该对象的时候可以在前面加const关键字 class CTest { public: void SetValue() {} private: int ...
- C++中常量成员函数的含义
C++中常量成员函数的含义 本文内容来源:<C++必知必会> 使用常量成员函数可以改变对象的逻辑状态,虽然对象的物理状态没有发生改变.考虑如下代码,它定义了一个类X: class X{ p ...
- 常量成员函数的注意事项 & mutable的使用场景
mutable的使用场景: 可以在一个const的对象里面,解除对部分字段的const限制.也可以用在const成员函数里面. 对于const与否,一般会调用不同版本的函数: 而对于二元操作符,如果用 ...
- C++ 必知必会:条款16 指向成员函数的指针并非指针
这一点与指向成员的指针类似,其实现可能更加复杂,因为成员函数同时还存在虚拟函数,需要动态绑定执行动作.当然这种属性是属于函数本身的,此处表达的是指针不涉及函数的属性问题. 1: class shape ...
- c++ 学习之const专题之const成员函数
一些成员函数改变对象,一些成员函数不改变对象. 例如: int Point::GetY() { return yVal; } 这个函数被调用时,不改变Point对象,而下面的函数改变Point对象: ...
- C++ Const成员函数
一些成员函数改变对象,一些成员函数不改变对象. 例如: int Point::GetY() { return yVal; } 这个函数被调用时,不改变Point对象,而下面的函数改变Point对象 ...
- 类 this指针 const成员函数
C++ Primer 第07章 类 7.1.2 Sales_data类的定义如下: #ifndef SALES_DATA_H #define SALES_DATA_H #include <st ...
随机推荐
- 解决Cannot change version of project facet Dynamic Web M
dynamic web module 版本之间的区别: Servlet 3.0 December 2009 JavaEE 6, JavaSE 6 Pluggability, Ease of devel ...
- R 网页数据爬虫1
For collecting and analyzing data. [启示]本处所分享的内容均是笔者从一些专业书籍中学习所得,也许会有一些自己使用过程中的技巧.心得.小经验一类的,但远比不上书中所讲 ...
- 记录php日志
1.记录PHP错误日志 display_errors与log_errors的区别 display_errors 错误回显,一般常用于开发模式,但是很多应用在正式环境中也忘记了关闭此选项.错误回显可以暴 ...
- [python学习笔记]Day2
摘要: 对象 对于python来说,一切事物都是对象,对象基于类创建: 注:查看对象相关成员 var,type,dir 基本数据类型和序列 int内部功能 class int(object): def ...
- 设计模式之桥接模式(Bridge)
注:本文不属于原创,而是根据原文重新整理,原文是:我给媳妇解释设计模式:第一部分 设计模式不是基于理论发明的.相反,总是先有问题场景,再基于需求和情景不断演化设计方案,最后把一些方案标准化成“模式”. ...
- 六个创建模式之抽象工厂模式(Abstract Factory Pattern)
问题: 使用工厂方法模式的主要问题是工厂类过多,每个产品对应一个工厂,不利于维护.因此可以考虑使用一个工厂创建一个产品族. 定义: 提供创建一些列相关或相互依赖的对象实例的接口,这些类可以称为一个产品 ...
- Hexo建博小结
本来只写在自己的github pages中的,想一想万一有人看呢,虽然同类的文章有不少了,但有些新坑他们没填啊,姑且放出来啦... 拥有自己的博客是一个很酷的事情,但自己建站总是太麻烦了,步骤繁多,管 ...
- 在ALV中更新数据库表
FORM usercommand USING ucomm TYPE sy-ucomm selfield TYPE slis_selfield. DATA: lr_grid TYPE REF TO cl ...
- 实验12:Problem C: 重载字符的加减法
Home Web Board ProblemSet Standing Status Statistics Problem C: 重载字符的加减法 Problem C: 重载字符的加减法 Time ...
- SharePoint 2013 - REST API about Content
1. 获取所有子站点信息(Sub Site): var subSitesInfo = "{0}/_api/Web/WebInfos?$orderby=Title desc"; // ...