深入解析 const 关键字:指针、参数、返回值和类成员函数

文章目录

  • const 关键字的理解
  • 一、 修饰普通类型的变量
  • 二、const 修饰指针变量
  • 三、const 作参数传递 和 函数返回值
    • (1)const 修饰函数参数
    • (2)const 修饰函数返回值
  • 四、const修饰类成员函数
  • 结尾

const 关键字的理解

const 在 C++ 中是用来修饰内置类型变量自定义对象成员函数返回值函数参数

C++中, const允许指定一个语义约束,编译器会强制实施这个约束,允许程序员告诉编译器某值是保持不变的。如果在编程中确实有某个值保持不变,就应该明确使用const,这样可以获得编译器的帮助。

使用const有以下好处:

  1. 编译器的静态检查:const 可以让编译器在编译时进行静态检查,确保不会对被声明为 const 的值进行修改。如果尝试修改 const 值,编译器将产生错误或警告。

  2. 代码可读性和维护性:使用 const 可以清晰地表达代码的语义,指出某个值不会被修改。可以提高代码的可读性,并且在维护代码时能够更好地理解和推理代码的含义。

  3. 防止意外修改:通过使用 const,可以避免在代码中意外地修改某个值。特别是当多人协作开发或者代码规模较大时,const 可以起到约束和保护的作用,防止错误的修改。

  4. 优化机会:const 还给编译器提供了一些优化机会,因为编译器知道 const 值不会被修改,可以进行一些相关的优化操作,提高程序的执行效率。

👇下面我们看const 关键字的使用👇


一、 修饰普通类型的变量

观察下面的代码:

const int a = 10;
int b = a; // 正常赋值
a = 20; // 错误,不能给常量赋值

当使用const修饰普通类型的变量a时该变量a会被编译器看成常量,而对常量赋值是违法的。

当我们写出如下的代码时,会发生一些出乎意料的情况:

在这里插入图片描述

我们发现,尽管在监视中a的值为20,但最终输出结果依然为10。

这是因为 编译器对常量的优化处理将常量 a 存储在只读内存区域,并且优化后的指令可能直接使用常量的值。虽然通过指针修改了数据,但是由于常量 a 是不可修改的,所以它的值仍然保持着 10。


上面的例子告诉我们,在c++中,尽量不要修改const修饰的变量。
但我们可以使用volatile 关键字,即下面的写法:

volatile const int a = 10;

当执行上面的代码时,最后结果会输出 “a的值为:20”

这是因为 volatile 关键字告诉编译器,这个变量的值可能会被意外地修改,因此每次使用这个变量时都要从内存中读取,而不是使用已经存在的寄存器中的值。如果没有使用
volatile,编译器可能会对这个变量进行一些优化,例如缓存这个变量的值,这样就无法保证每次使用这个变量时都是最新的值。


二、const 修饰指针变量

const 修饰指针变量有三种情况:

① const 修饰指针指向的内容,则内容为不可变量。
② const 修饰指针,指针为不可变量。
③ const 同时修饰指针和指针指向的内容,指针和指针指向的内容都为不可变量。


对于 ①:

const修饰的常量指针:指针本身是一个常量,不能修改指向的地址,但可以修改指向地址所存储的值。

// 理解为: const在int*前,所以
int a = 10, b = 20;
const int* ptr = &a;// 修改指向地址所存储的值是合法的
*ptr = 20; // 错误,编译器会报错// 修改指向的地址是不合法的
ptr = &b; // 合法,可以修改指针指向的地址

对于②:

const修饰的指针常量:指针指向的是一个常量,不能通过指针修改所指向地址处的值,但可以修改指针指向的地址。

int a = 10, b = 20;
int* const ptr = &a;// 修改指向地址所存储的值是合法的
*ptr = 20; // 合法,可以修改指向地址处的值// 修改指针指向的地址是不合法的
ptr = &b; // 错误,编译器会报错

对于③:

const同时修饰指针和常量:既不能修改指针本身,也不能通过指针修改所指向地址处的值。

int a = 10, b = 20;
const int* const ptr = &a;// 修改指向地址所存储的值是不合法的
*ptr = 20; // 错误,编译器会报错// 修改指针指向的地址是不合法的
ptr = &b; // 错误,编译器会报错

三、const 作参数传递 和 函数返回值

(1)const 修饰函数参数

const 修饰 函数参数有以下三种情况:

  1. const修饰的值传递参数
void func(const int num) {// 不能修改num的值// ...
}

在这种情况下,形参 num 被声明为常量,函数内部不允许修改它的值。


  1. const修饰的指针传递参数
void func(const int* ptr) {// 不能修改ptr所指向地址处的值// ...
}

这里 ptr 是一个指向常量整数的指针,函数内部不能通过指针修改所指向地址处的值,但可以修改指针本身。


  1. const修饰的引用传递参数
void func(const int& ref) {// 不能修改ref所引用的值// ...
}

在这种情况下,引用 ref 被声明为常量,函数内部不允许修改它所引用的值。


(2)const 修饰函数返回值

const 修饰返回值一样有下面三种情况:

  1. const 修饰返回值为常量:
const int func() {// ...return 10;
}

在这种情况下,函数 func() 的返回值被声明为常量,外部代码不能修改返回值。


  1. const 修饰返回指针类型的函数
int* const func() {// ...static int num = 10;return #
}

这里 int* const 表示返回值是一个指向整数的常量指针。使用 const 修饰的指针表示指针本身的值是常量,外部代码不能修改指针指向的地址。但可以通过指针修改所指向地址处的值。


  1. const 修饰返回引用类型的函数
const int& func() {// ...static int num = 10;return num;
}

在这种情况下,返回值是一个指向整数的常量引用。使用 const 修饰的引用表示外部代码不能通过引用修改其所引用的对象。


四、const修饰类成员函数

const 修饰类成员函数,其目的是防止成员函数修改被调用对象的值,如果我们不想修改一个调用对象的值,所有的成员函数都应当声明为 const 成员函数。

注意:const 关键字不能与 static 关键字同时使用,因为 static 关键字修饰静态成员函数,静态成员函数不含有 this 指针,即不能实例化,const 成员函数必须具体到某一实例。


有下面两种类型:

  1. const 修饰返回引用类型的函数
class MyClass {
public:void func() const {// ...}
};

在这种情况下,成员函数 fnc() 被声明为 const 成员函数。const 成员函数表示该函数不会修改类的成员变量。

在 const 成员函数中,不能修改非静态成员变量(除非是 mutable 修饰的成员变量),也不能调用非 const 的成员函数。


  1. const 修饰返回值为常量的成员函数
class MyClass {
public:int getValue() const {// ...return value;}
private:int value;
};

在这种情况下,成员函数 getValue() 被声明为 const 成员函数,并且返回值的类型是 const。这表明该成员函数不会修改类的成员变量并且返回值在外部代码中不能被修改


结尾

使用 const 修饰类成员函数可以提供额外的安全性和约束,通过 const 修饰的成员函数,编译器可以对其进行一些优化,在某些情况下还能够调用 const 成员函数来访问 const 对象。同时,也能够帮助开发人员识别和避免意外的修改操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/128052.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于SVM+TensorFlow+Django的酒店评论打分智能推荐系统——机器学习算法应用(含python工程源码)+数据集+模型(一)

目录 前言总体设计系统整体结构图系统流程图 运行环境Python环境TensorFlow 环境方法一方法二 安装其他模块安装MySQL 数据库 模块实现1. 数据预处理1)数据整合2)文本清洗3)文本分词 相关其它博客工程源代码下载其它资料下载 前言 本项目以支…

好物周刊#19:开源指北

https://github.com/cunyu1943/JavaPark https://yuque.com/cunyu1943 村雨遥的好物周刊,记录每周看到的有价值的信息,主要针对计算机领域,每周五发布。 一、项目 1. Vditor 一款浏览器端的 Markdown 编辑器,支持所见即所得、…

三十一、【进阶】B+树的演变过程

1、B树简单介绍 (1)介绍:B树也属于B树,是B树的变种 (2)特点:所有的数据都位于叶子节点上,叶子节点上的所有元素形成了一个单项链表 (3)图示: 2…

Spring源码解析——IOC属性填充

正文 doCreateBean() 主要用于完成 bean 的创建和初始化工作,我们可以将其分为四个过程: 最全面的Java面试网站 createBeanInstance() 实例化 beanpopulateBean() 属性填充循环依赖的处理initializeBean() 初始化 bean 第一个过程实例化 bean在前面一篇…

LVGL_基础控件checkbox

LVGL_基础控件checkbox 1、创建checkbox /* 创建一个 checkbox 部件(对象) */ lv_obj_t * cb lv_checkbox_create(lv_scr_act()); // 创建一个 switch 部件(对象),他的父对象是活动屏幕对象 lv_checkbox_set_text(cb, "100ASK LVGL Tutorial" LV_SYMBOL_PLAY);…

多功能频率计周期/脉宽/占空比/频率测量verilog,视频/代码

名称:多功能频率计周期、脉宽、占空比、频率测量verilog 软件:Quartus 语言:Verilog 代码功能: 多功能频率计,可测量信号的周期、脉冲宽度、占空比、频率,语言为verilog,quartus软件设计仿真…

tailscale自建headscale和derp中继

tailscale derp中继服务简介 tailscale是一个基于WireGuard的零配置软件,它可以轻松地在多台设备之间建立点对点加密连接。 derp服务器是tailscale网络的重要组成部分。它作为tailscale客户端之间的中继,帮助客户端找到并连接到其他客户端设备。 但Tailscale 官方…

华为云API自然语言处理的魅力—AI情感分析、文本分析

云服务、API、SDK,调试,查看,我都行 阅读短文您可以学习到:人工智能AI自言语言的情感分析、文本分词、文本翻译 1 IntelliJ IDEA 之API插件介绍 API插件支持 VS Code IDE、IntelliJ IDEA等平台、以及华为云自研 CodeArts IDE&a…

扭线机控制

扭线机属于线缆加工设备,线缆加工设备种类非常多。有用于网线绞合的单绞,双绞机等,有关单绞机相关算法介绍,大家可以查看专栏相关文章,有详细介绍,常用链接如下: 线缆行业单绞机控制算法&#…

电脑散热——液金散热

目录 1.简介 2.传统硅脂与液金导热区别 3.特点 4.优点 5.为什么液金技术名声不太好 6.使用方法 1.简介 凡是对于电脑基础硬件有所了解的人,都知道硅脂是如今高性能电脑设备中必不可少的东西。芯片表面和散热器接触面,虽然肉眼看上去是非常光滑的金属…

[VIM]spcaevim

Home | SpaceVim SpaceVim - 知乎 关于Vim/Neovim/SpaceVim的一些思考 - 知乎 vim高配版(1) – SpaceVim 简介 SpaceVim 是国内的一个大佬将一些NB的插件整合到一起的一个插件包. 一键式安装, 功能强大. 官网参见 Home | SpaceVim vim高配版(2) – vimplus 简介 vimplu…

正则验证用户名和跨域postmessage

正则验证用户名 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>登录</title> </head> <body> <input type"text" name"username" placeholder"用户名…