C++中const的用法

news2024/11/18 3:42:41

const 我们都见过,但是今天,我们会从头开始重新再说const的所有用法。

一、const修饰普通变量

当我们定义一个变量时,前面加上const修饰的话,这个变量将不再能被修改,称之为常变量。例如:

int a=10;
a=20;

const int b=10;
int const c=10;
b=20;

在上述代码中,a称之为变量,b称之为常变量。变量修改没有任何问题,但是常变量有“常”属性,不能被修改,所以下面两行是错误的。

另外,常变量必须初始化

int a;
a=10;
a=20;

const int b;
b=10;

你觉得,我定义一个常变量,然后后面再对他进行赋值能对嘛,答案是:不能! 

const可以代替一些宏:

#define MAX_NUMBER 1e8
const long long MAX_NUMBER=1e8;

为什么写起来宏更方便,我们还要用const,我只能告诉你:const更加安全。

const修饰普通变量很常用,也很简单,除了记得必须初始化外,需要注意的点也不多。

二、const修饰指针变量

好嘛!这第二个就开始说const与指针的事了,这简直就是羊了个羊的难度跨越。const修饰指针跟羊了个羊一样,看起来规则就这,但其实玩起来,那需要注意的就多了,用的时候小心点就ok了。

1.常量指针

(常指针)常量指针实质顾名思义就是一个指针,但是我们不能通过指针去修改指向的变量,所以这个指针就是常量指针。来看一下语法:

int a=10;
const int *p=&a;

//或者你也可以这么写
int const *p=&a;

但无论上边哪种写法,我们都可以发现一个问题,const真正修饰的不是变量p,而是*p,*p是什么,不就是p指向的内存的内容嘛,const修饰了,那我们就不能修改了。但p这个指针的指向可以改变,指向别的变量:

int a=10;
int b=20;

const int p=&a;
p=&b;

这么写是没有任何问题的。但同样的,不管p指向哪块儿内存,都不能修改p指向的内容,只能修改p的指向,p也成了常量指针,它的意义就是防止通过指针修改变量。 

2.指针常量 

 指针常量就是一个常量,这个常量表示一个指针,也就是这个常量的数据内容是一个地址信息。什么意思呢?看代码:

int a=10;
int b=20;

int* const p=&a;
p=&b;

聪明的同学又开始提前思考了,这次const的位置发生改变了,这次改变后,const后面紧跟着的就是指针p,那就是说,p不能改变。p=&b那行代码就会报错,于是就去VS上试验了一番,想法正确。对的,这位聪明的同学,你的想法完全正确,你以实践验证想法的做法也让我欣赏万分。

那这次,既然这次我们修饰的是指针变量p,那么p的初始化能不能省去呢?不能的,这次修饰的是变量本身,而非变量内容,修饰变量本身,本身的值是无法被修改的。但是,对应的,我们可以利用指针来改变指针的指向内容:

int a=10;
int* const pa=&a;
*p=30;
cout<<a<<endl;//a=30;

 p就是一个存地址的变量,地址不可以被修改。那p的作用是什么,其实p的作用就是修改p指向的内容。在传参时,为了安全考量,我们的地址不能丢失,但是我们还需要这个地址来修改内容。使用cosnt这样修饰的话,我们就能解决上述问题。这看起来好像引用类型,没错,引用就是C++给大家封装好的的指针常量。这就是引用类型的实质,引用必须初始化,那是因为指针常量就是这样的,引用不能改变引用关系,你看,指针常量不也是吗,不能修改指向内容。

3.“双常”

int a=10;
const int* const p=&a;

const哪都跑,真烦人呐,哈哈,不要烦,你就看const修饰谁就完了,修饰*p,那么*p不能变,修饰p,那么p不能变。那要是都修饰,都不变呗。以后这个p 就是a的内存,*p就是a。意义不太大了,p和*p就是&a和a。

*拓展知识

随时拓展,但也不多,总结下来就没几句话,我的习惯,看完代码好说事。来看看下面哪个是正确的写法? 选吧,A or B or C。

const int a =10;

int *pa=&a;//A
const int*pb=&a;//B
int* const pc=&a;//C

答案是B,为什么?a由const修饰,代表着a不可改,只有B选项符合条件。如果用另外两个指针存储a的地址,我们可以通过指针解引用来改变a的值,const属性就没有意义了,C++是一门严谨的编程语言,语法要求比较严格。

那我int a=10; 能用cosnt int *pa=&a;来存嘛,可以的。来看结论吧:(!!非常重要!!

总结:指针指向的变量,const属性不能丢失,但可以增加。

三、const修饰引用变量

//左值引用:DataType& _a;
//右值引用:DataType&& a;
//万能引用:const DataType & aa;
int test01() {
	int a = 10;
	return a;
	//返回:数值,右值
}
int& test02() {
	static int a = 10;
	return a;
	//返回:引用,左值
}
int main() {
	int _a = 2;//_a是左值
	int& a = _a;//(左值引用)引用左值
	int&& b = 2;//(右值引用)引用右值
 
	//int&& b2 = _a;//(右值引用)不能引用左值
	//int& a2 = 2;//(左值引用)不能引用右值
 
	const int& aa = test01();//(万能引用)引用右值
	const int& bb = test02();//(万能引用)引用左值
	return 0;
}

我们函数传参时,有时候会传入左值,有时候会传入右值,我们传入的还需要是引用类型的数据,那么万能引用才是合适的形参。const又又又又来了,哈哈,用的时候就在引用类型前面加一个const就行了,没那么难。上述左值右值,引用的方法你了解一下就行,(先点赞收藏一波,嘻嘻^_^)等有需要再来看看就行了呗。 

const int num = 10;//num是一个int型的常量
const int &n = num;//正确,n是一个常量引用,并且num本身也是一个常量
n = 20;//错误,引用被const限制了,不能修改所引用对象的值了
int &n2 = num;//错误,试图让一个非常量引用指向一个常量对象

int a=50;
const int &n=a;//正确,可以增加const属性
//所以万能引用的实质就是const属性虽不可去除但可以增加的特性

四、const修饰函数

严格意义上cosnt不能修饰除成员函数外的函数,这里只是修饰函数的构成要素:参数/返回值等

1.修饰函数参数

const修饰参数,在函数内就不可以修改参数的值了,就是修饰上面说的三种情况。

2.修饰函数返回值

修饰返回值干嘛?你问这个问题的时候就知道你没想过返回引用类型的时候是怎么个事。

让我们先做一下准备工作:来看一下引用类型返回值的情况:

int& fun(int& a){
    a+=10;
    return a;
}

这么看,好像啥也没有,就跟简单的返回值没啥区别,那再看一下这个代码:

int main(){
    int a=10;
    fun(a)=a+10;
    cout<<a;
    return 0;
}

这就没怎么见过了吧,我什么时候见过函数调用完后放在等号左面的啊?这不就见了吗,fun返回的就是a的引用,我通过a的引用去修改了a的值。

慢慢琢磨吧,学习的路途,任重而道远。

五、const修饰成员函数

const修饰的成员函数,称为常函数

第一个问题:const修饰符放在哪里?

我们上面说过const修饰函数的问题,但那修饰的不是参数就是返回值,我们到底怎么修饰整个函数呢?const放到哪里合适呢?

放在函数名前面是修饰返回值,不行。放在参数列表,修饰的是形参,不行。放在函数名和参数列表中间?不行啊,函数名和括号中间除了空格以外,不能加修饰符跟其它任何东西啊。放到大括号内部?那就是函数体的一部分了,也不可以。ok那就只有一个地方了:函数后,大括号之前。

int fun() const{
    
}

当然了,这种写法只在类(结构体)内生效 。

 好了,现在我们知道了如何修饰成员函数。那么接下来我们就要说:

第二个问题:这么修饰有什么作用?

常函数的函数体内,不能有修改类内成员属性的代码。也就是说,常函数的意义在于成员变量被该类的函数修改。比如:有一个函数的功能就是为了判断这个类实例化的对象是不是空的,只有判断功能的函数,不应该修改成员属性,此时加上const,就能有效避免问题了。

关键字:mutable。类内成员声明时使用mutable修饰,常函数就有了该成员的修改权限。

第三个问题:常函数有什么特点?

特点一:常函数不能调用调用非常函数

如果一个常函数调用非常函数,非常函数改变了成员属性,不管怎么说这也是在常函数中修改了成员属性,这不允许。

所以这个特点要切记:类内的常函数不可调用类内的非常函数。(实质是,有更改类内属性的风险)。

实质:常函数调用非常函数,常函数的*this的const常属性被去掉了,这是不允许的。

而非常函数可以调用常函数,非常函数的*this增加了const属性,是允许的,可以看一下上文修饰指针的拓展知识。

特点二:同名同参的常函数与非常函数可以构成重载

函数相同,参数相同,常属性不同,构成重载

实质:this指针不同,即显式参数相同,但隐式参数不同,属于参数列表不一样,发生重载

注意:常对象只能调用常函数,非常对象优先调用非常函数

特点三:常函数的this指针和非常函数的this指针不同

常函数的隐藏this指针为:cosnt className* const this

非常函数的隐藏this指针为:className* const this

看字看不懂?配个代码吧:

class A{
    int num;
pulic:
    void work(){
        //非-常函数
        this->num=2;//非常函数更改成员属性
        fun();//yes,快去试试调用的是哪个fun()吧
        cout<<"work"<<endl;
    }
    void fun() const{
        //常函数
        //num=2;//改不了
        //work();//error
        cout<<"const fun"<<endl;
    }
    void fun() {
        //构成重载关系
        cout<<"fun"<<endl;
    }
};

六、const修饰对象

const修饰的对象,称为常对象

声明类变量时(这个变量就是对象),前面加上const 修饰,这个对象就是常对象。

常对象只能调用常函数。但普通对象可以调用常函数和非常函数

实质:传参时,常对象的this的const属性不能被去掉,所以this无法向非常函数传参,就不能调用非常函数。而普通对象调用常函数传this时,增加const属性,合法。

一样的,给个代码(类取上面那段代码)

int main(){
    A a;//非常对象,可以调用所有在访问权限内的函数(包括常函数)
    const A b;//常对象

    a.fun();//非常对象优先调用非常函数
    b.fun();//常对象只调用常函数
    return 0;
}

感谢大家!cosnt的所有用法基本都在了,可以说是相当全的了。建议收藏,哈哈,当然有更全的也可以在评论区留个言,那什么,我也是需要学习的,与诸君共勉 (^_^)!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ESD分类和等级划分

1、HBM&#xff1a;Human Body Model&#xff0c;人体模型 2、CDM&#xff1a;Charged Device Model&#xff0c;充电器件模型 3、MM&#xff1a;Machine Model&#xff0c;机器模型&#xff1a; 数据来源网站

总结Java文件操作

文件&#xff1a;文件是一个广义的概念 在操作系统中文件可以指硬件资源和软件资源为文件&#xff1b;也可以指存储在硬盘上的文件&#xff0c;文件夹也是文件&#xff1b;文件夹是通俗的叫法&#xff0c;专业的叫法是目录&#xff1b; 查看我们的硬盘&#xff0c;我们可以发…

C语言分析数据在内存中的存储一:(整形在内存中的存储)

数据类型介绍 我们知道C语言有很多内置类型&#xff1a; char //字符数据类型 1 个字节short //短整型 2 个字节int //整形 4 个字节long //长整形 4 个字节long long //更长的整形 8 个字节float //单精度浮点数 4 个字节dou…

Linux学习记录(十三)----信号

文章目录 6.信号1.信号的发送&#xff08;发送信号进程&#xff09;kill:raise:alarm : 2.信号的接收3.信号的处理信号父子进程间通信 7.信号灯(semaphore)创建信号灯函数控制信号灯函数PV操作 声明&#xff1a;本人撰写的为学习笔记内容来源于网络&#xff0c;如有侵权联系删除…

SQL Server中如何自动抓取阻塞

背景 当发数据库生阻塞时&#xff0c;可以通过SQL语句来获取当前阻塞的会话情况&#xff0c;可以得到下面的信息 说明&#xff1a;会话55阻塞了会话53。两个会话都执行了update test set fid10 where fid0。 但我们也经常碰到客户生产环境出现阻塞&#xff0c;由于不会抓取或者…

YOLOv8实现任意目录下命令行训练

问题 当你使用YOLOv8命令行训练模型的时候&#xff0c;如果当前执行的目录下没有相关的预训练模型文件&#xff0c;YOLOv8就会自动下载模型权重文件。这个是一个正常操作&#xff0c;但是你还会发现&#xff0c;当你在参数model中指定已有的&#xff0c;在其他目录下的预训练模…

实际案例:某日化集团主数据建设项目

一、建设背景1. 背景分析当前&#xff0c;该日化企业集团的主数据尚处于分散状态&#xff0c;分布于各业务系统中&#xff0c;缺乏一套专业的主数据管理系统进行统一管理。因此&#xff0c;数据无法在全集团范围内共享使用&#xff0c;且在业务端到端的流程拉通时&#xff0c;数…

WPS关闭后,进程依然在后台运行的解决办法

问题 wps启动后 在启动wps后&#xff0c;什么都不做&#xff0c;打开进程管理器&#xff0c;发现居然运行了3个wps进程&#xff1a; win10只会显示wps进程&#xff1a; win11显示比较准确&#xff1a; 关闭后 在关闭wps&#xff0c;再去任务管理器查看&#xff0c;发现在…

游戏开发设计模式之策略模式

目录 策略模式在游戏开发中的具体应用案例有哪些&#xff1f; 如何在Unity中实现策略模式以优化角色行为和AI策略&#xff1f; 策略模式与其他设计模式&#xff08;如观察者模式、状态模式&#xff09;在游戏开发中的比较优势是什么&#xff1f; 策略模式的优势 观察者模式…

基于SpringBoot的闲一品交易平台

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot框架 Java技术 工具&#xff1a;IDEA/Eclipse、Navicat、Maven 系统展示 首页 管理员…

【手撕OJ题】——160. 相交链表

目录 &#x1f552; 题目⌛ 方法① - 遍历记录链表长度⌛ 方法② - 双指针 &#x1f552; 题目 &#x1f50e; 160. 相交链表【难度&#xff1a;简单&#x1f7e2;】 &#x1f50e; 面试题 02.07. 链表相交 &#x1f50e; 剑指 Offer 52. 两个链表的第一个公共节点 给你两个单…

hadoop集成spark(spark on yarn)

文章目录 hadoop集成spark&#xff08;spark on yarn&#xff09;下载spark软件包spark文件设置spark-env.shworkers 环境变量设置发送spark到其余机器启动spark hadoop集成spark&#xff08;spark on yarn&#xff09; 在hadoop搭建完成的前提下&#xff0c;集成spark&#x…

【面试题系列Vue02】Vue Router 路由都有哪些模式?各模式之间有什么区别?

官方解析 Vue Router 路由有三种模式&#xff1a; hash 模式&#xff1a;使⽤ URL 中的 hash&#xff08;即 # 后面的内容&#xff09;来作为路由路径。 在这种模式下&#xff0c;页面不会重新加载&#xff0c;只会更新 hash 值&#xff0c;并触发路由变化&#xff0c;从而渲…

c语言杂谈系列:模拟虚函数

从整体来看&#xff0c;笔者的做法与之前的模拟多态十分相似&#xff0c;毕竟c多态的实现与虚函数密切相关 废话少说&#xff0c;see my code&#xff1a; kernel.c#include "kernel.h" #include <stdio.h>void shape_draw(struct shape_t* obj) {/* Call dr…

气膜粮仓:卓越的抗风雪能力与高性能材料—轻空间

在粮食储存领域&#xff0c;气膜粮仓以其卓越的抗风雪能力和高性能材料成为了现代农业的首选。其独特的设计和先进的材料使其在各种极端天气条件下依然能够保证粮食的安全和品质。 强抗风雪能力&#xff0c;保障粮仓安全 气膜粮仓采用了创新的结构设计&#xff0c;能够有效抵御…

Selenium + Python 自动化测试19(补充-读取各种文件数据操作)

我们的目标是&#xff1a;按照这一套资料学习下来&#xff0c;大家可以独立完成自动化测试的任务。 上一篇我们讨论了数据驱动测试中如何完成重复的测试实例&#xff0c;今天我们补充一些读取各种文件的方法。 本篇文章我们讨论一下如何使用读取txt、CSV、Excel文件&#xff0…

burpsuite xssValidator插件(xss插件)

安装 1. 商城安装插件 2. 安装环境 Download PhantomJShttps://phantomjs.org/download.htmlGitHub - NetSPI/xssValidator: This is a burp intruder extender that is designed for automation and validation of XSS

halcon1

Halcon安装&#xff1a;halcon介绍&#xff1a; 德国MVtec公司开发的一套完善的标准的机器视觉算法包。底层功能算法多&#xff0c;运算性能快。halcon不能提供相应的界面编程需求&#xff0c;需要和vs一起才能构成一套完整软件。 软件界面 halcon数据类型 Halcon的数据类型主…

Hugo博客搭建

Hugo 构建 Hugo 安装 下载 安装包hugo version 查看是否安装成功 生成站点基础框架 进入自己指定文件夹下执行 hugo new site solejay-blog创建仓库 cd solejay-blog git init主题配置 进入 Hugo 主题页面 选择主题并下载 个人喜欢的主题&#xff1a;meme、newsroom、gal…

mac安装java17(jdk17)

1. 下载jdk17 官网下载&#xff1a;https://www.oracle.com/java/technologies/downloads 2. 直接安装 安装完后目录会存放在下面目录下 /Library/Java/JavaVirtualMachines 111111deMBP JavaVirtualMachines % ls jdk-11.0.227 jdk-17.jdk 3. 如果你已经安装过java&#…