掘根宝典之C语言和C++中的const

 const的基本概念


const名叫常量限定符,用来限定特定变量,以通知编译器该变量是不可修改的。

习惯性的使用const,可以避免在函数中对某些不应修改的变量造成可能的改动。

const修饰基本数据类型

2.1 const修饰一般常量及数组

int const a = 100;
const int a = 100; //与上面等价
int const arr [3] = {1,2,3};
const int arr [3] = {1,2,3};//与上面等价

对于这些基本的数据类型,修饰符const可以用在类型说明符前,也可以用在类型说明符后,其结果是一样的。

2.2 const修饰指针(*)

主要有以下几种类型:

char *p = "hello";     // 非const指针,// 非const数据const char *p = "hello";  // 非const指针,// const数据char * const p = "hello";   // const指针,// 非const数据const char * const p = "hello";  // const指针,// const数据


2.2.1 常量指针

当为常量指针时,不可以通过修改所指向的变量的值,但是指针可以指向别的变量。

int a = 5;
const int *p =&a;
*p = 20;   //error  不可以通过修改所指向的变量的值int b =20;
p = &b; //right  指针可以指向别的变量


2.2.2 指向常量的指针(指针常量)

当为指针常量时,指针常量的值不可以修改,就是不能指向别的变量,但是可以通过指针修改它所指向的变量的值。

int a = 5;
int *const p = &a;
*p = 20;     //right 可以修改所指向变量的值int b = 10;
p = &b;      //error 不可以指向别的变量


2.2.3 总结

如果const位于星号*的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;

如果const位于星号*的右侧,const就是修饰指针本身,即指针本身是常量。

2.2.4具体举例


代码如下:

#include<stdio.h>
int main()
{int a = 10, b = 20;int* p1 = &a;    //可以修改值 也可以修改方向*p1 = 100;p1 = &b;const int* p2 = &a;   //指向//int x2=*p2;//*P2=100;//error//p2=&b;int const* p3 = &a;//const 在指针前 修饰指向方向可以读取值 自身值可以改变int* const p4 = &a;//int x=*p4;// *p4=100;//p4=&b;//error//const 在指针后 修饰值本身 p4的值不可以改变 但是后面修饰的值可以const int* const p5 = &a;//指针前有指针后也有 均不可以改变return 0;
}



 const修饰函数


const 在函数中根据修饰的位置分为三种:函数参数、函数返回值、成员函数。

const  int fun (const int a) const;



3.1 const修饰函数参数


修饰函数形参;函数体内不能修改形参a的值。

如果函数作为输出用,不论是什么数据类型,也不论采用指针传递还是引用传递,都不能加const 修饰,否则参数会失去输出功能。

所以:const 只能修饰输入作用的参数

3.1.1 如果参数为指针

如果输入参数为指针,加上const之后就会起保护指针意外修改的作用。

void StringCopy(char* strDest, const char* strSource);

在这个函数定义中,我们的的参数strsource加上const修饰,就是为了防止strsource被修改。

可以起到保护作用的原因是:
实参中,指针会指向一段内存地址,调用函数之后,函数会产生一个临时指针变量,这个变量的地址与实参的地址不一样,但是这两个指针指向的内存是同一块。形参加上const 修饰之后,保护了这一块内存地址不被修改,如果刻意修改这一块内存,编译器会报错。

3.1.2 如果参数为引用

如果输入参数为引用,加上const 之后既起到了保护作用,也提高了程序效率。

void func(Y y);//这里的Y类型为用户定义的类型
void func(Y &y);//采用引用的方式

调用这个函数我们会产生一个临时对象,随后调用拷贝构造函数,当函数结束的时候,进行析构释放资源。

如果改成引用void func(A &a); 只是相当于实参的一个别名,不会产生临时变量。

所以,如果是自定义类型,建议用引用作为函数形参。

3.2 const修饰函数返回值
修饰返回值,就是不能修改返回值

3.2.1 值传递

如果是值传递,没有必要将返回值用const修饰

const int func();



对于函数来说,它的返回值为一个int类型的值,是一个临时的值没有必要用const修饰。

3.2.2 返回值为指针


如果返回值为指针,加上const修饰后,同样的内容是不可以修改的。

这个时候我们接收的变量也必须是const修饰:

const char* func();
char* str = func();// error 
const char* str = func(); //right


3.2.3 返回值为引用

如果返回值为引用,也可以提高效率。但是一般返回引用的地方并不是很多,一般会出现在类的赋值函数中。而且,用const 修饰返回值为引用类型的更少。一般来说不常用。

3.3 const修饰成员函数


const 修饰的成员函数为了保护成员变量,要求const 函数不能修改成员变量,否则编译会报错。
函数体内不能修改成员变量的值,增加程序的健壮性或鲁棒性。只有成员函数才可以在后面加const,普通函数后加const无意义。

class MyClass {
public:void func(int x) const;
};



const函数的规则

  1. const 对象只能访问const 成员函数,非const 的对象可以访问任何成员函数,包括const 成员函数。
  2. 如果函数名、参数、返回值都相同的const成员函数和非const成员函数是可以构成重载,那么const对象调用const成员函数,非const对象默认调用非const的成员函数。
  3. const成员函数可以访问所有成员变量,但是只能访问const的成员函数。
  4. 非const成员函数,可以访问任何成员,包括const成员成员函数。
  5. const成员函数不能修改任何的成员变量,除非变量用mutable修饰。

类中定义变量(const的特殊用法)


在类中实现常量的定义大致有这么几种方式实现:使用枚举类型,使用const或static

4.1使用枚举类型

class test
{enum { a = 10, b = 20}; // 枚举常量int array1[a];  int array2[b];
};



4.2 使用const或static


C++11仅不允许在类声明中初始化static非const类型的数据成员。

// using c++11 standard
class CTest11
{
public:static const int a = 3; // Ok in C++11static int b = 4;       // Errorconst int c = 5;        // Ok in C++11int d = 6;              // Ok in C++11
public:CTest11() :c(0) { }     // Ok in C++11
};int main()
{CTest11 testObj;cout << testObj.a << testObj.b << testObj.c << testObj.d << endl;return 0;
}



4.3 总结


在不同的标准下 是略微有所不同的

  1. 对于static const 类型的成员变量不管是旧的C++标准还是C++11都是支持在定义时初始化的。
  2. 对于static 非const类型的成员变量C++03和C++11的标准都是不支持在定义时初始化的。
  3. 对于const 非static类型的成员变量C++03要求必须在构造函数的初始化列表中来初始化,而C++11的标准支持这种写法,同时允许在定义时进行初始化操作。
  4. 对于非static 非const成员变量,C++03标准不允许在成员变量定义时初始化,但是C++11标准允许在类的定义时对这些非静态变量进行初始化。
  5. 对于static非const成员变量的初始化方式并未改变,就是在相应的cpp文件中写成int CTest11::b = 5即可,注意要在类定义之后。

五 使用const的好处


可以定义const常量

这样可以避免由于无意间修改数据而导致的编程错误,提供了一个保护作用。

便于进行类型检查

const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换时可能会产生意料不到的错误。

为函数重载提供了一个参考

const修饰的函数可以看作是对同名函数的重载。

可以节省空间,避免不必要的内存分配

const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象宏一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而宏定义的常量在内存中有若干个拷贝。

提高了效率

编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期的常量,没有了存储与读内存的操作,使得它的效率也很高。

 const在C和C++中的区别


在C语言中,用const修饰的变量,其本质上还是个变量,只是它不允许作为左值存在,也就是不法对该变量进行直接赋值修改该变量,但是这不意味着该变量的值就无法修改。

在C++中 ,在编译的时候,当碰到用const修饰的变量时,编译器是直接将变量的值和变量的符号对应起来一起存到符号表。

例如const int a = 5;在符号表中就会将a和5对应起来,在编译的过程中,当碰到printf(“a = %d\n”,a); 时,用 5 直接将 a 替换掉。在C++中,编译器不会为a分配存储空间,在C语言中就会为a分配存储空间,所以在C编译器中,就可以通过指针来改变用const修饰的变量。

其实在C++中,const修饰的变量,在编译的时候如果前面有extern和取地址符 & 时,会为变量分配存储空间是为了兼容C语言,但是在C++中,用const修饰的变量就真的无法修改它的值,可以说是常量。

但是在C语言中,const修饰的变量本质上还是变量而不是常量。

这在C语言中其实也是矛盾的,因为我们想要用const定义一个常量,但又可以通过指针来改变该常量的值。

而C++为了兼容C语言,所以保留了这个特性,但是却无法修改它的值,这就是const在C语言和C++中的区别。

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

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

相关文章

MAth类与Random类

Math类 Math类是Java编程语言中的一个工具类&#xff0c;它包含了一系列用于执行基本数学运算的静态方法&#xff1b;由于Math类中构造方法的访问权限是private&#xff0c;所以无法创建Math类的对象&#xff1b;Math类中的所有方法都是静态方法&#xff0c;可以通过类名直接调…

CSS复合选择器(三)

伪元素选择器 作用&#xff1a;选中元素中的一些特殊位置。 常用伪元素&#xff1a; ::first-letter 选中元素中的第一个文字。::first-line 选中元素中的第一行文字。::selection选中被鼠标选中的内容。::placeholder 选中输入框的提示文字。::before 在元素最开始的位置&…

1.BOM-获取元素(获取元素、修改属性)

web Api基本认知 作用&#xff1a;通过JS去操作html页面和浏览器(实现浏览器中的某些功能) 分类&#xff1a; DOM(网页)&#xff1a;Document Object Model(文档对象模型) BOM(浏览器)&#xff1a;Borwser Object Model(浏览器对象模型) DOM DOM树 将网页中标签的关系以树状…

利用excel批量修改图片文件名

今天同事提出需求要实现利用excel批量修改某文件夹下的图片重命名&#xff0c;衡量到各种条件&#xff0c;最后还是选择了vbs来实现。代码如下 代码 创建Excel对象 Set objExcel CreateObject("Excel.Application") objExcel.Visible False 隐藏Excel窗口 打开Ex…

react:usecontext使用

useContext返回 调用组件上方最近的 SomeContext.Provider 的 value 如果没有这样的 provider 传递给 createContext 的 defaultValue。返回的值始终是最新的。 如果 context 发生变化&#xff0c;React 会自动重新渲染读取 context 的组件。 <Context.Provider> 需要位于…

【MySQL知识体系】第2章 数据库与表的创建(一)

第2章 数据库与表的创建 2.1 数据库操作 2.2 表操作 文章目录 第2章 数据库与表的创建2.1 数据库操作2.1.1 创建第一个数据库2.1.2 更新数据库名称&#xff08;数据库创建后无法修改名称&#xff09;2.1.3 删除数据库2.1.4 取个合适的数据库名称 第2章 数据库与表的创建 2.1 数…

990-40产品经理:What Is Effective Written Communication? 什么是有效的书面沟通?

The purpose of written communication is to capture your reader’s attention and get your point across clearly. Ultimately, when you communicate in writing, you are helping the reader understand your perspective看法 on a topic. There are certain qualities a…

在 echarts 的 rich 中使用 iconfont 图标库图标作为 backgroundColor.image 值的方法

实现步骤 1、引入 iconfont.js。该脚本执行时&#xff0c;会在 body 下插入一个 svg 标签&#xff0c;标签下包含了图标库中的 svg 图标 path。 <script src"your/iconfont/path/iconfont.js"></script>或者 import your/iconfont/path/iconfont.js2、…

【学习心得】websocket协议简介并与http协议对比

一、轮询和长轮询 在websocket协议出现之前&#xff0c;要想实现服务器和客户端的双向持久通信采取的是Ajax轮询。它的原理是每隔一段时间客户端就给服务器发送请求找服务器要数据。 让我们通过一个生活化的比喻来解释轮询和长轮询假设你正在与一位不怎么主动说话的老大爷&…

基于R语言lavaan的SEM在复杂统计建模中的科研技术新突破

此外&#xff0c;我们还将深入探讨R语言的基础知识、结构方程模型的基本原理、lavaan程序包的使用方法等内容。无论是潜变量分析、复合变量分析&#xff0c;还是非线性/非正态/缺失数据处理、分类变量分析、分组数据处理等复杂问题&#xff0c;我们都将一一为您解析。 希望通过…

3.7作业

网络聊天室&#xff1a; 程序代码&#xff1a; ser.c #include <myhead.h> //定义消息类型结构体 struct xiaoxi {char type;char name[20];char text[100]; };int main(int argc, const char* argv[]) {// 创建套接字int sfd socket(AF_INET, SOCK_STREAM, 0);if (s…

Spring源码:手写AOP

文章目录 一、概念1、AOP是什么&#xff1f;2、相关概念1&#xff09;目标对象Target2&#xff09;通知Advice3&#xff09;连接点Joinpoint4&#xff09;切点Pointcut5&#xff09;切面Aspect6&#xff09;织入Weaving 二、分析三、实现1、实现Advice1&#xff09;前置通知2&a…

蓝桥杯-Stack

Stack实例化步骤 1导包&#xff0c;导入java.util.* 2实例化对象&#xff0c;格式如下 Stack<引用数据类型> stacknew Stack<>(); Stack特点&#xff1a;先进后出。比如1&#xff0c;2&#xff0c;3依次入栈&#xff0c;出栈顺序就是3&#xff0c;2&#xff0c…

企业微信HOOK协议,新设备二次验证处理

提示设备强制二次验证问题已处理 HOOK&#xff1a;https://www.showdoc.com.cn/1663062930779972/7859611259700402密码&#xff1a;999999999

大数据冷热分离方案

数据冷热分离方案 1、背景 ​ 随着业务的发展&#xff0c;在线表中的数据会逐渐增加。常规业务都有冷热数据现象明显的特性&#xff08;需要访问的都是近期产生的热数据&#xff1b;时间久远的冷数据出于备份、备案溯源等诉求会进行在线保留&#xff09;。在业务表数据 量可控…

安卓玩机工具推荐----高通芯片9008端口读写分区 备份分区 恢复分区 制作线刷包 工具操作解析

上期解析了下adb端口备份分区的有关操作 安卓玩机工具推荐----ADB状态读写分区 备份分区 恢复分区 查看分区号 工具操作解析 在以往的博文中对于高通芯片机型的分区读写已经分享了很多。相关类似博文 安卓备份分区----手动查询安卓系统分区信息 导出系统分区的一些基本操作 …

设计模式之构建者模式

构建者模式&#xff08;Builder&#xff09; 定义 将一个复杂对象的构建与其表示分离&#xff0c;使得同样的构建过程可以创建不同的表示 使用场景 主要角色 产品 Product建造者接口 Builder具体的建造者 Concrete Builder指挥者 Director:组织构建过程 示例代码 Data p…

0x04_数组_指针_字符串

数组 数组的定义与使用 数组是具有一定顺序关系的若干相同类型变量的集合体&#xff0c;组成数组的变量称为该数组的元素。 给出下面程序的输出&#xff1a; #include <iostream> using namespace std; int main() {int a[10], b[10];for(int i 0; i < 10; i) {a[…

Redis高可用方案

Redis的高可用架构模式及相关配置命令是构建稳定、可靠Redis环境的关键。以下是一些主要的Redis高可用架构模式及其配置方法&#xff1a; 主从复制&#xff08;Master-Slave&#xff09; 主从复制模式实现了Redis数据的备份和读取操作的负载均衡。在这个模式中&#xff0c;一台…

python 基础知识点(蓝桥杯python科目个人复习计划59)

今日复习内容&#xff1a;做题 例题1&#xff1a;建造房屋 问题描述&#xff1a; 小蓝和小桥是两位年轻的建筑师&#xff0c;他们正在设计一座新的城市。 在这个城市中&#xff0c;有N条街道&#xff0c;每条街道上有M个位置可以建造房屋&#xff08;一个位置只能建造一个房…