C++ 之 常量成员函数

2023-11-18

  常量成员函数 (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_(2016), m_(9), d_(22) {}

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

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

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

  根据成员变量的声明顺序,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(1);        // OK
int j = cd.GetYear(); // OK cd.AddYear(1); // 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(1); 
}

  这种做法虽然是可以的,但它破坏了使用 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 章

 

转载于:https://www.cnblogs.com/xinxue/p/5405362.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐

  • Codeforces Round 871 (Div. 4)G. Hits Different

    G Hits Different 题意 给一个如图所示的三角形 输入n 击倒方块n 获得分数n n 同时方块n上面的两个方块也会落下 同时获得这两个方块的分数 一直向上走 知道方块1 如图所示为n 9的时候掉落的方块 求获得的分数 思路 先
  • python对csv文件取特定列生成新csv文件

    import csv import os def file name in file out file reader csv reader in file header next reader data header format head
  • 用C语言写一个类似天天酷跑游戏(图形库用easyx)

    1 头文件 全局变量和结构体 a 玩家结构体 b 枚举玩家三种状态 奔跑 跳跃 滑行 c 障碍物结构体 d 障碍物结点 e 枚举出障碍物类型 include
  • Java做运维之配置多服务器间SSH免密登录

    Java做运维之配置多服务器间SSH免密登录 说明 第一步 引入依赖 第二步 编写核心操作类 1 RmtShellExecutor 2 CommonStringUtil 3 IoUtil 4 SshAccount 5 SshNoPwdUti
  • HTML、CSS及JS之间的区别浅谈

    HTML CSS 和 JS 是构建网页的三种核心技术 HTML Hypertext Markup Language 是一种标记语言 用于描述网页的结构和内容 通过 HTML 开发人员可以创建网页元素 例如标题 段落 列表 链接和图像等 CS
  • 嵌入式开发之移植MQTT到RK3568

    目录 前言 一 下载qmqtt源码 二 编译库文件 三 移植到RK3568 3 1 移植动态库libQt5Qmqtt 四 联机测试 4 1 制作demo 4 1 1 创建demo新项目 4 1 2 添加network模块支持 4 1 3 添
  • Mac下编译WebRTC(Mac和iOS版本)

    前言 随着新冠疫情的影响 这两年音视频的需求呈爆发式增长 在音视频领域中 WebRTC可以说是一个绕不开宝库 包括了音视频采集 编解码 传输 渲染的全过程 本文主要记录下在Mac平台上编译WebRTC Mac和iOS版本的全过程 设置代理
  • 网页设计大作业-五子棋游戏,可以进行双人对弈

    游戏如下动态图 下载链接在文末 点我免积分下载资源 资源链接 https download csdn net download weixin 43474701 34854310
  • tp886n设置虚拟服务器,TP-Link TL-WR886N V4-V5设置虚拟服务器方法

    本文主要介绍了TP Link TL WR886N V4 V5路由器上 设置虚拟服务器 端口映射 的方法 注意是V4 0和V5 0版本的TL WR886N路由器上虚拟服务器设置方法 因为 目前TL WR886N路由器有V2 0 V3 0 V4
  • 【华为OD机试真题 JAVA】第k个排列

    JS版 华为OD机试真题 JS 第k个排列 标题 第k个排列 时间限制 1秒 内存限制 262144K 语言限制 不限 给定参数n 从1到n会有n个整数 1 2 3 n 这n个数字共有 n 种排列 按大小顺序升序列出所有排列情况 并一一标记
  • vue 子组件未渲染完成,通过refs调用报错,解决办法。

    在 Vue 中 如果父组件调用子组件的方法时因为子组件未渲染完成而出现错误 一种解决方法是使用 nextTick 方法来等待子组件渲染完成后再进行操作 具体做法如下 在父组件中使用 ref 属性给子组件命名 例如 在模板中给子组件命名为 m
  • C++调用Python程序,无法解析的外部符号 __imp___Py_RefTotal

    C 调用python程序时 出现如下问题 无法解析的外部符号 imp Py RefTotal 无法解析的外部符号 imp Py NegativeRefcount 该符号在函数 import array 中被引用 这是由于安装的python为
  • Linux运维实战:Linux清理僵尸进程

    一 僵尸进程简介 官方解释 当子进程比父进程先结束 而父进程又没有回收子进程 释放子进程占用的资源 此时子进程将成为一个僵尸进程 一般在系统中僵尸进程的关键字为defunct或者dead 僵尸进程一般指进程已经死了或者已经停止运行了 但是它
  • Netty---入门程序,搭建Websocket 服务器

    Netty 常用的场景 1 充当HTTP 服务器 但Netty 并没有遵循servlet 的标准 反而实现了自己的一套标准进行Http 服务 2 RPC 远程调用 在分布式系统中常用的框架 3 Socket 长连接 需要了解的名词 1 Ni
  • 什么是RPC并实现一个简单的RPC

    1 基本的RPC模型 主要介绍RPC是什么 基本的RPC代码 RPC与REST的区别 gRPC的使用 1 1 基本概念 RPC Remote Procedure Call 远程过程调用 简单的理解是一个节点请求另一个节点提供的服务 本地过程
  • screen 使用

    screen 是一款能够实现多窗口远程控制的开源服务程序 基本使用 安装screen yum install screen 创建blackup会话 scrren S blackup 查看已有会话列表 screen ls 恢复会话 scree
  • RabbitMQ消息确认机制

    消息确认 基本流程 说明 生产者发送消息到RabbitMQ Server后 RabbitMQ Server需要对生产者进行消息Confirm确认 消费者消费消息后需要对 RabbitMQ Server进行消息ACK确认 消息确认模式 Rab
  • iterable java_如何在Java中将Iterable转换为Collection?

    iterable java There are various ways to convert Iterable to Collection in Java programming language 有多种方法可以用Java编程语言将Ite
  • BUUCTF--[第二章 web进阶]死亡ping命令

    BUUCTF 第二章 web进阶 死亡ping命令 本文只是对官方wp进行了一点修改 因为在测试过程中发现8080端口弹不回flag 在本地测试也是一样的结果 但是把端口修改成8089 其他端口应该也可以 并且nc监听方式为 nc lvp
  • C++ 之 常量成员函数

    常量成员函数 const member function 可读取类中的数据成员 但不能修改 1 声明 1 1 const 关键字 参数列表后 加 const 关键字 声明为常量成员函数 表明其不被允许修改类的数据成员 下面的类 以年 月 日