C++:常量

const的最初动机

const的使用方法

使用const的好处是允许指定一种语义上的约束,即某种对象不能被修改,且由编译器具体实施这种约束。
const声明格式:const 类型名 对象名;修饰普通变量,时期不能被随意修改
【注意】1.C++中的const为内部连接,即由const定义的常量仅在被定义的文件中才能看见,除非使用extern。一般情况下,编译器不为const分配空间(而extern则强制分配空间)。
2. 当定义一个常量(const)时,必须进行初始化,即赋初值给它,除非已经用extern最清楚说明。
可以使用const修饰数组,表示“常”数组,即数组的值不能被修改。例如

const int data[] = { 1, 2, 3 };//合法使用,定义一个常量数组
struct MyStruct
{int i, j;
};
const MyStruct mList[] = { {1, 2}, {3, 4} };//定义一个结构体常量数组
data[0] = 10;  //错误
mList[1].i = 4;//错误

同时,定义上述数组后,对常数组的一下引用也是错误的。

char cList[data[2]];//错误
float fList[mList[0].i];//错误

错误原因在于,在编译时编译器必须为数组分配固定大小的内存。而用const修饰的数组意味着“不能被改变”的一块存储区,但其值在编译期间不能被使用。

const与指针

const与指针的结合使用由两种情况:1.用const修饰指针,即修饰存储在指针里的地址;2.修饰指针指向的对象。
为了防止使用混乱,采用“就近原则”,即const距离哪个近就修饰哪个:若const距离变量近,则表示的含义为指向常量的指针;若const距离指针近,则表达的含义为指向变量的常指针。

指向常量的指针

定义格式:const 类型名* 指针变量名;或者类型名 const* 指针变量名;这两种格式是等价的。

const int data = 10;
const int *p = &a;
*p = 20; //错误
const int max = 20;
p = &max; //正确

表明p是一个指向const int的指针。指针所指向的单元不能修改,但是其本身为指针变量可以指向别的位置。

常指针

定义格式为:类型名 *const 指针名;

int i = 1;
int * const p = &i;

表明p是一个常指针,一个指向int类型的变量i的const指针,p必须用一个初值,它只能指向这个初始对象i,不能“被改变”而指向其他对象,但对象的值可以被修改。
同时,不仅可以使用一个常指针指向一个变量,也可以把非const对象变成const对象。例如:

int a = 10;
int *const p = &a;      //可以用const指针指向一个非const对象
const int *const q = &a;//可以把const对象地址赋值给const对象指针

const与函数

函数与const的结合使用由两种方式:1.参数为const类型;2.返回值为const类型。

const类型的参数

定义格式:返回值类型 函数名称(const 类型 参数名,···)例如:

void f(const int  i){i++;//错误
}

当c++在函数的参数使用引用时,需要特别注意对常量引用的使用。例如:

void f1(int&) {}
void f2(const int&) {}
int main() {f1(1);//错误,在f1()中,可以修改参数内容,而1为常量f2(1);//正确,在f2()中,参数声明为常量int n = 10;const int m = 11;f1(n);//正确f1(m);//错误,不能使用普通引用方式引用常量f2(n);//正确,可以用常量方式引用普通常量f2(m);//正确return 0;
}

const类型的返回值

可以用const修饰函数的返回值,即函数返回一个常量值,此常量值即可以赋给常量(对常量初始化),也可以赋给变量。其对返回值为某个类对象时,会显得尤为重要。
常对象的使用:

class MyClass
{
public:MyClass(int i = 0):data(i){}void seti(int i) {data = i;}
private:int data;
};
MyClass test1() {return MyClass();//返回为普通对象
}
const MyClass test2() {return MyClass();//返回为常对象
}
int main() {test1() = MyClass(10);//正确,test1()返回一个MyClass对象,并把对象MyClass(10)的值赋给它test1().seti(20);//正确,调用test1(),得到一个返回对象,并调用此对象的成员函数seti()test2() = MyClass(10);//错误,常对象不能被修改(赋值)test2().seti(20);//错误,常对象不能被修改return 0;
}

const与类

const在类里有两种应用:1.是在类里建立类内局部常量,可用在常量表达式中,而常量表达式在编译期间被求职;2.是const和类成员函数的结合使用。

类内const局部常量

在一个类内使用const修饰的意思就是“在这个对象的寿命期内,这是一个常量。”然而,对这个常量来讲,每个不同的对象可以含有一个不同的值。
在类内建立一个const成员时不能赋初值,只能在构造函数里面对其赋初值,而且要放在构造函数的特殊地方,因为const必须在创建它的地方被初始化,所以在构造函数的主体里,const成员必须已被初始化。例如:

class MyClass
{
public:MyClass():num(100){}
private:const int num;
};

常用的一种情况就是,在类内声明一个常量,用这个常量来定义数组的大小,把数组的大小隐藏在类内。
错误示范:

class MyClass
{
public:MyClass();
private:const int num = 100;//错误int data[100];//错误
};

因为在类内进行存储空间分配时,编译器无法知道const的内容是什么,所以不能把它用于编译期间的常量。
解决这种问题的方法有两种:

  1. 静态常量。为提高效率保证所有的类对象最多只有一份拷贝值,通常需要将常量声明为是静态的。例如:
class MyClass{static const int num = 100;int mList[num];
};
  1. enum(枚举常量)。例如:
class MyClass{enum{num = 100};int data[num];
};

常对象与常成员函数

声明一个“复杂”的对象为常量,对于公有数据这点很容易做到,然而对于私有数据,该如何保证每个成员函数的调用不改变呢?需要声明这个成员函数为const类型,等同于告诉编译器此类的一个const对象可以调用这个成员函数,而const对象调用非const成员函数。
const成员函数定义格式:class 类名{返回值类型 成员函数名称(参数列表) const;};
【注意】若在函数的前面加上const,则表明函数返回值为const,为防止混乱,应把const放在函数的后面。在一个const成员函数里,试图改变任何数据成员或调用非const成员函数,编译器都将显示出错误信息。
例如:const成员函数与非const成员函数使用方式的比较。

//student.h
#ifndef STUDENT_H_//防止重复包含头文件student.h
#define STUDENT_H_
class Student{int No;char Name[20];
public:Student();int GetNo() const;//const成员函数const char* GetName();//返回值为const的成员函数,不是const成员函数
};
#endif
//student.cpp
#include <string.h>
#include <student.h>
Student::Student(){No = 1;strcpy(Name, "wang");
}
int Student::GetNo()const{return No;
}
const char* Student::GetName(){return Name;
}
//test.cpp
#include <student.h>
int main(){Student s1;s1.GetNo();s1.GetName();const Student s2;s2.GetNo();//正确,常对象调用const成员函数s2.GetName();//错误,常对象调用了非const成员函数return 0;	

然而,有时候我们需要修改对象的某些数据成员时该怎么办?有两种方法.
1.强制转换。在常成员函数中修改成员变量的值。

class Test{int i, j;
public:Test():i(0),j(0){};void f()const;
};
void Test f()const{i = 1; //错误,在常成员函数中修改类成员((Test*)this)->j = 5; //正确
}
int main(){const Test t;t.f();//正确return 0;
}
  1. 使用mutable,用它指定某个特定的数据成员在常量对象的某个函数里是可以被修改的。在常成员函数中修改有mutable所修改的变量值。
class Test{int i;mutable int j;
public:Test():i(0),j(0){};void f()const;
};
void Test f()const{i = 1; //错误,在常成员函数中修改类成员j = 5; //正确,可以在常成员函数中修改被mutable修饰的类成员
}
int main(){const Test t;t.f();//正确return 0;
}

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

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

相关文章

探索大模型时代下的文档识别与分析【GPT4-V带来的挑战与机遇】

中国图象图形学学会青年科学家会议是由中国图象图形学学会青年工作委员会发起的学术会议。本会议面向国际学术前沿与国家战略需求&#xff0c;致力于支持图象图形领域的优秀青年学者&#xff0c;为青年学者们提供学术交流与研讨的平台&#xff0c;促进学者之间的交流与合作。会…

深入理解C#中的引用类型、引用赋值以及 `ref` 关键字

深入理解C#中的引用类型、引用赋值以及 ref 关键字 在C#编程中&#xff0c;理解引用类型、引用赋值以及 ref 关键字的使用对于编写高效、可靠的代码至关重要。本文将深入探讨这些概念&#xff0c;帮助您更好地理解C#的工作原理。 引用类型简介 在C#中&#xff0c;所有的类型都…

MySQL的事务机制

一、事务机制简述 事务机制,避免写入直接操作数据文件&#xff1b;利用日志来实现间接写入&#xff0c;与事务有关的, redo日志与undo日志&#xff1b;sql语句操作记录复制到undo日志然后增删改查操作的结果会记录在redo日志&#xff0c;如果操作没有什么问题就把数据同步到数…

【MySQL】MySQL版本8+ 的 with recursive 递归语法初次使用

力扣题 1、题目地址 1613. 找到遗失的ID 2、模拟表 表&#xff1a;Customers Column NameTypecustomer_idintcustomer_namevarchar customer_id 是该表主键.该表第一行包含了顾客的名字和 id. 3、要求 编写一个解决方案, 找到所有遗失的顾客 id。遗失的顾客 id 是指那些…

代码随想录算法训练营第三十天 | 332.重新安排行程、51. N皇后、37. 解数独

332.重新安排行程 题目链接&#xff1a;332.重新安排行程 给你一份航线列表 tickets &#xff0c;其中 tickets[i] [fromi, toi] 表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。 所有这些机票都属于一个从 JFK&#xff08;肯尼迪国际机场&#xff09;出发的…

安卓fragment监听文本内容取值

首先需要自己定义一个最大的BaseFragment&#xff0c;继承这个BaseFragment并在骑宠填充你需要绑定的Fragment class LoginFragment : BaseFragment<FragmentLoginBinding>(R.layout.fragment_login) { }顶自己需要获取的值 private lateinit var account: EditTextpriv…

Prometheus C++使用教程

1 简介 Prometheus是一个包括时序数据库的工具&#xff0c;可以将指标Metric数据传入Prometheus&#xff0c;然后通过Grafana可视化出来。 Grafana是一个通用的数据看板&#xff0c;可以通过自定义的看板&#xff0c;实时的观察各类指标的变化。 2 安装Prometheus 2.1 安装d…

综合指南:理解气体检测仪的关键功能和单位换算

随着科技的飞速发展&#xff0c;气体检测仪在各行各业中的应用已十分普遍&#xff0c;其主要用途是检测环境中的气体浓度。 1、检测气体纯度 主要用于气体储罐、管道等储运设备中检测气体的纯度&#xff0c;一般都是专门针对高纯气体的浓度值进行检测&#xff0c;常见的如氩气…

C语言数组基础知识

目录 一维数组&#xff1a; 一维数组的创建&#xff1a; 一维数组的访问&#xff1a; 一维数组在内存中的存储&#xff1a; 二维数组&#xff1a; 二维数组的创建&#xff1a; 二维数组的初始化&#xff1a; 二维数组的使用&#xff1a; 二维数组在内存中的存储&#x…

部署Gitea服务的那些坑

目标&#xff1a;在win10系统上部署Gitea服务&#xff0c;以ssh协议的方式访问。 首先要在win10系统上安装ssh服务&#xff0c;这里安装OpenSSH即可&#xff0c;PowerShell脚本如下&#xff08;记住管理员运行&#xff09;&#xff1a; # 打开 PowerShell 以管理员身份运行 #…

为什么会有js?

JavaScript&#xff08;简称为JS&#xff09;是一种脚本语言&#xff0c;主要用于为网页添加交互性和动态效果。JS的出现主要有以下几个原因&#xff1a; 网页交互性的需求&#xff1a;早期的静态网页只能展示信息&#xff0c;无法与用户进行交互。随着互联网的发展&#xff0c…

上海晋名室外暂存柜助力石墨烯材料行业气瓶储存安全

近日上海晋名又有一台室外气瓶暂存柜项目通过验收&#xff0c;此次项目主要用于石墨烯材料行业气瓶的室外暂存。 用户单位创立于2017年&#xff0c;是一家从事石墨烯等新材料技术的科技型高新技术企业。 上海晋名作为一家专注工业安全防护领域&#xff0c;危险化学品安全储存…

JavaScript-内置对象-笔记

1.Math对象 Math对象&#xff1a; 用于进行数字处理 自带的对象 不是构造函数---不需要new 属性&#xff1a; Math.PI ----- 圆周率 方法&#xff1a; Math.floor(数字) ----- 向下取整 &#xff08;只要整数位&#xff09; Math.ceil(数字) ---- 向上取整&#xff08;不管小数…

web安全之XSS攻击原理及防范

XSS攻击原理 XSS&#xff08;Cross-Site Scripting&#xff0c;跨站脚本攻击&#xff09;是一种常见的网络攻击方式。攻击者通过在受害者的浏览器中注入恶意脚本&#xff0c;来实现对受害者的会话劫持、敏感信息窃取等非法目的。但是在实际的项目开发中&#xff0c;除了少数企…

RocketMQ Dashboard可视化工具

RocketMQ Dashboard 将 RocketMQ的相关指标展示在web页面 &#xff0c;支持以可视化工具代替 Topic 配置、Broker 管理等命令行操作。 官方文档地址&#xff1a;RocketMQ Dashboard | RocketMQ 目录 1.下载安装 1.1 系统要求&#xff1a; 1.2 源码安装 1.3 访问页面 2.功…

如何搭建开源知识库软件AFFiNE并实现公网环境远程协作【内网穿透】

目录 前言 1. 使用Docker安装AFFINE 2. 安装cpolar内网穿透工具 3. 配置AFFINE公网访问地址 4. 实现公网远程访问AFFINE 结语 作者简介&#xff1a; 懒大王敲代码&#xff0c;计算机专业应届生 今天给大家聊聊如何搭建开源知识库软件AFFiNE并实现公网环境远程协作【内网穿…

借势API电商数据采集汇总分析

电商数据采集的网页抓取数据、淘宝、天猫、京东等平台的电商数据抓取&#xff0c;网页爬虫、采集网站数据、网页数据采集软件、python爬虫、HTM网页提取、APP数据抓包、APP数据采集、一站式网站采集技术、BI数据的数据分析、数据标注等成为大数据发展中的热门技术关键词。那么电…

使用python读取yaml文件数据

使用python读取yaml文件&#xff1a; yaml文件数据&#xff1a;data.yaml login_data:url: http://www.baidu.comcase1:user1: password1: 12345errorText: 请输入用户名case2:user2: adminpassword2: errorText: 请输入密码case3:user3: adminpassword3: 123456errorText: 登…

ABAP CDS 笔记

文章目录 1.什么是abap cdsadap cds的优点 2.常用cds语法常用函数一 数值函数1.绝对值2. 最小整数不小于arg的值3.两个参数相除4.两个数相除切保留小数位5.最小整数不大于arg的值6.取除数的余数 二 字符串函数1.拼接字符2.替换字符3.截取字符串 三 常用的分支语句1.CASE 表达式…

19. 从零用Rust编写正反向代理, 配置数据的热更新原理及实现

wmproxy wmproxy是由Rust编写&#xff0c;已实现http/https代理&#xff0c;socks5代理&#xff0c; 反向代理&#xff0c;静态文件服务器&#xff0c;内网穿透&#xff0c;配置热更新等&#xff0c; 后续将实现websocket代理等&#xff0c;同时会将实现过程分享出来&#xff…