c++ const 总结
前言
- const 的作用很多,而且在被用作 常量指针 和 指针常量 的时候经常容易搞混,今天就来总结一下 所有 const 的用法;
一、const 在普通变量中的应用
1、修饰内置类型
i)左右皆可
- const 修饰内置类型时,位置出现在 变量类型 的左边或者右边,其含义一样,代表被修饰的对象是一个常量,生命周期内不能被改变;
const int maxn = 1024;int const maxm = 1024;
复制代码
ii)常量的非法修改
- 直接通过赋值修改常量,编译器会报错;
- 但是我们可以通过取地址的方式取得常量的地址,然后再强转成 int 指针,再在对应地址上去取值修改,然后在 watch 窗口观察,发现变量的值的确被修改了!!!但是用 printf 打印出来还是原来的值,所以说明这是一种未定义行为,编译器没想到你会干出这种事,写代码的时候应该坚决避免;
const int maxn = 1024;*((int *)&maxn) = 1;printf("%d\n", maxn); // 1024
复制代码
2、修饰指针类型
i)常量指针
- 定义:是一个指针,指针变量指向常量;
- 记忆方法:常量(const)在指针(*)左边,所以从左往右跟我读:常量指针!
- 特性:指向的对象不可变;类型 和 const 的相对位置可以交换;
const int cInt = 1024;const int* p = &cInt;*p = 43; // 错误行为,企图修改指针指向对象
复制代码
ii)指针常量
- 定义:是一个常量,指针常量指向变量;
- 记忆方法:指针(*)在常量(const)左边,所以从左往右跟我读:指针常量!
- 特性:指针本身不可变;
int iInt;int * const q = &iInt;q = &iInt; // 错误行为,企图修改指针本身
复制代码
iii)常量指针常量
- 定义:是一个指针常量,指针常量指向常量;
- 记忆方法:常量(const)、指针(*)、常量(const)从左往右读!(这个名字是我编的)
- 特性:指针本身不可变,指向对象亦不可变;
const int cw = 1024;const int * const w = &cw;
复制代码
3、修饰引用类型
i)常量引用
- 定义:是一个引用,并且值不能被修改;
- 引用就是变量的 “别名” ,必须被初始化,并且需要初始化为已有的变量,但是当它被限定为 const 常量以后,可以被初始化为常量;但是一旦初始化以后,引用的值就不能被修改了;
int cw = 1024;const int& cw1 = cw;const int& cw2 = 4;cw = 5; // 正确行为cw1 = 6; // 错误行为,引用在初始化以后值不能被修改cw2 = 7; // 错误行为,引用在初始化以后值不能被修改
复制代码
ii)引用常量
- 定义:不存在;
int cw = 1024;int& const cc = cw;
复制代码
- 编译后报警告:warning C4227: anachronism used : qualifiers on reference are ignored
- 原因是引用实质是一个指针常量,所以已经不需要用 const 修饰了;
二、const 在函数中的应用
1、修饰函数传参
- 函数传参 作为 常量 传入的目的,主要是为了函数的调用不要修改实参的值;
i)内置类型参数
- 函数传参会拷贝一份数据,所以对于内置类型来说,加上 const 作用不大;
void XFunc(const int x) {printf("%p\n", &x);
}int x;
printf("%p\n", &x);
XFunc(x);
复制代码
008FFD80
008FFCA0
- 可以看到,输出的实参和传参的地址是不同的,所以不用担心函数的调用会修改实参的值;
ii)指针类型参数
- 指针传入的时候,实际是传入对应类型对象的一个地址;
- 传指针的好处是,函数传递过程中不需要进行类的构造和析构;
- 希望传递的对象本身不被修改,就传常量指针;希望传递的指针本身不被修改,就传指针常量;
class A {
public:A() {}A(int a) {}
};
void YFunc(const A *x, A *const y) {*x = 1; // 错误行为*y = 1; // 正确行为x = NULL; // 正确行为y = NULL; // 错误行为
}
复制代码
iii)引用类型参数
- Effective C++ 一书中曾反复提到,宁以 pass-by-reference-to-const 替换 pass-by-value,说的就是函数作为常引用传参;
- 当以引用的形式传入参数的时候,并且不希望函数内部修改对应参数的值,那就加上 const 限定符;
- 最经典的例子就是类的拷贝构造函数;
class B {
public:B() {}B(const B& other) {i = other.i;}
private:int i;
};B b1;
B b2(b1);
复制代码
2、修饰函数返回值
- const 修饰返回值和传参的相似之处不再累述;
- 这里举个例子来说明,如果期望返回值不被修改,但是又没有加 const 造成的一些困扰;
class AddObject {
public:AddObject() {v = 0;}AddObject(int iv) {v = iv;}const AddObject operator+(const AddObject& other){v += other.v;return *this;}...
private:int v;
};
复制代码
AddObject a, b, c;if(a + b = c) {...}
复制代码
- 这里如果类 AddObject 的 返回值不定义成 const ,那么上面那个表达式将会成为未定义行为,仅仅是因为把 “==” 写成了 “=” ;
三、const 在类中的应用
1、修饰成员变量
i)声明即定义
- 可以在常量被声明的时候直接初始化他的值;
- 一般类变量如果定义为 const,代表不会变,那么可以加上 static 关键字,所有对象公用一个数据;
class InitTest {
public:InitTest() {}
private:const int a = 1;
};
复制代码
ii)初始化列表
- 修饰成员变量的时候,可以在构造函数的初始化列表(initialization list)中将 const 常量初始化;
class InitTest {
public:InitTest() : a(2) {}
private:const int a;
};
复制代码
2、修饰成员函数
i)修饰方式
- 当修饰类的成员函数时,const 放置在函数声明(圆括号后)和函数体(花括号前)之间;
- 含义是:这个函数中所有的非静态(non-static)成员变量的值都不允许被修改;
class ConstTest {
public:ConstTest() {}void setval(int iv) {v = iv;}int getval() const {return v;}
private:int v;
};
复制代码
- 思考题:如果有两个成员函数实现同样的功能,一个是const成员函数,一个是非const成员函数,那么为了避免代码冗余,比较常用的做法是:一个函数调用另一个?那么请问,应该是谁调用谁?
四、const 在 STL 中的应用
- STL 是 Standard Template Library 的简称,中文名:标准模板库;
- 其中 迭代器 是 STL 里面一种遍历容器的指针;
1、常量迭代器
- std::vector< T >::const_iterator 等同于 const T*,是一个常量迭代器,迭代器指向的数据不可被更改;
std::vector<int>::const_iterator iter1 = vec.begin();*iter1 = 13; // 错误行为iter1 = vec.end(); // 正确行为
复制代码
2、迭代器常量
- const std::vector< T >::iterator 等同于 T* const,是一个迭代器常量,迭代器本身不可被更改;
const std::vector<int>::iterator iter2 = vec.begin();*iter2 = 13; // 正确行为iter2 = vec.end(); // 错误行为
复制代码
五、const 和 #define 的区别
- | const | #define |
---|---|---|
实现原理 | 走C++语法 | 不走C++语法,单纯进行字符替换 |
类型检查 | 有 | 无 |
处理阶段 | 编译阶段 | 预处理阶段 |
存储方式 | 存储在符号表 | 不存储 |
六、突破 const 限定
1、mutable 关键字
- 还是以成员函数为例,如果 const 成员函数中,期望某些非静态成员变量能够改变,则加上 mutable 关键字即可;
class ConstTest {
public:ConstTest() {}void setval(int iv) {v = iv;}int getval() const {++c;return v;}
private:int v;mutable int c;
};
c++ const 总结相关推荐
- c/c++中的const
关于const能否修改 c语言 #include <stdio.h> int main() {const int i = 10;//const int i; //错误,const变量必须在 ...
- 微信小程序var,let,const的区别
var 用var的方式声明的变量,为全局变量 let 声明块级变量,即局部变量 const 用于声明常量,也具有块级作用域 const PI=3.14;
- js中定义变量之②var let const的区别
var 上一篇文章有讲过,是js定义变量的关键词. 但是在es6中,新添加了两个关键词,用于变量声明的关键词:let 和const 接下来就说一下var let 和const的区别: 首先说var 用 ...
- C++ 笔记(15)— 引用(声明引用、引用作为参数、引用作为函数返回值、const 用于引用)
引用是变量的别名.也就是说,它是某个已存在变量的另一个名字.一旦把引用初始化为某个变量,就可以使用该引用名称或变量名称来指向变量. 1. 创建引用 要声明引用,可使用引用运算符 & ,如下面的 ...
- C++ 笔记(07)— 常量(字面常量、const定义常量、constexpr 定义常量、enum 定义常量、define 定义常量)
在 C++ 中,常量类似于变量,只是不能修改.与变量一样,常量也占用内存空间,并使用名称标识为其预留的空间的地址,但不能覆盖该空间的内容. 常量可以是任何的基本数据类型,可分为整型数字.浮点数字.字符 ...
- Const 重载解析
1. Const重载应用场景 首先,对于函数值传递的情况,因为参数传递是通过复制实参创建一个临时变量传递进函数的,函数内只能改变临时变量,但无法改变实参.则这个时候无论加不加const对实参不会产生任 ...
- 【C++自我精讲】基础系列二 const
[C++自我精讲]基础系列二 const 0 前言 分三部分:const用法.const和#define比较.const作用. 1 const用法 const常量:const可以用来定义常量,不可改变 ...
- C++const关键字作用
修饰普通变量,表示不可修改(在定义的时候必须初始化) #include <iostream> using namespace std; const int a1 = 10; int mai ...
- const与define相比优点_const与#define的区别、优点
const与#define的区别 编译器处理方式不同 define宏是在预处理阶段展开. 补充:预处理器根据以#开头的命令,修改原始的程序.比如我们常见的#include 命令告诉处理器读取系统头文件 ...
- inline函数返回值_C++知识补充-指针,const,函数指针,指针数组,运算符重载
嵌入式Linux:C++ 面试准备珍藏版本zhuanlan.zhihu.com 明月照我心:123道c++笔试题汇总(含答案)zhuanlan.zhihu.com 阿贵:常见C++笔试面试题整理 ...
最新文章
- 线性回归与梯度下降法——原理与实现
- 【Nginx】错误: [emerg] “proxy_pass“ cannot have URI part in location given by regular expression,...
- Android Studio 3.3 Beta提供了新的Android代码压缩器R8
- linux man 后面的数字,man命令后面的数字
- NHibernate配置 使用经验
- struts教程笔记6
- 【VRP】基于matlab禁忌搜索算法求解初始点和终点确定的取送货路径问题【含Matlab源码 1224期】
- 重启Windows的PowerShell
- ASP.NET ASHX 一般处理程序教程
- 智能聊天对话机器人的对比
- linux redis-trib.rb,redis集群配置 执行 redis-trib.rb 报错解决方法
- mmap内存映射原理
- 惠普f5静音键指示灯不亮(转载)
- 第8讲 - C语言关键字(8)
- IE文档模式的切换,Quirks模式
- python 学习之Windows 下的编码处理!
- 设计,看上去很美 wayfarer
- linux如何修改用户密码(passwd)
- 深富策略:消费白马迎来反攻 能否配置?
- 5G图传设备VR+5G直播4K+5G直播
热门文章
- djangoday02
- 求出小于45岁的各个老师所带的大于12岁的学生人数
- 关于Maven项目里所有代码凭空消失的问题
- XXL-Job执行器部署
- 生成伪随机数的函数int rand(void)和void srand(unsigned seed);
- Java中原生(native)函数的用法
- MPLS拓扑设计与VRF、RD、RT详解
- carsim中质心加速度_CarSim仿真快速入门(七)—车辆参数化建模
- 伯乐在线 android,伯乐在线博客
- 美国GeneSiC推出目前世界最高等级6.5kV/300mΩ SiC MOSFET产品