C++ const 全网最全总结(推荐)
2021/5/31 20:21:29
本文主要是介绍C++ const 全网最全总结(推荐),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
文章目录
- 前言
- 一、const 在普通变量中的应用
- 1、修饰内置类型
- i)左右皆可
- ii)常量的非法修改
- 2、修饰指针类型
- i)常量指针
- ii)指针常量
- iii)常量指针常量
- 3、修饰引用类型
- i)常量引用
- ii)引用常量
- 二、const 在函数中的应用
- 1、修饰函数传参
- i)内置类型参数
- ii)指针类型参数
- iii)引用类型参数
- 2、修饰函数返回值
- 三、const 在类中的应用
- 1、修饰成员变量
- i)声明即定义
- ii)初始化列表
- 2、修饰成员函数
- i)修饰方式
- 四、const 在 STL 中的应用
- 1、常量迭代器
- 2、迭代器常量
- 五、const 和 #define 的区别
- 六、突破 const 限定
- 1、mutable 关键字
前言
- 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 全网最全总结(推荐)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-01UniApp 中组件的生命周期是多少-icode9专业技术文章分享
- 2024-11-01如何使用Svg Sprite Icon简化网页图标管理
- 2024-10-31Excel数据导出课程:新手从入门到精通的实用教程
- 2024-10-31Excel数据导入课程:新手入门指南
- 2024-10-31RBAC的权限课程:新手入门教程
- 2024-10-31Svg Sprite Icon课程:新手入门必备指南
- 2024-10-31怎么配置 L2TP 允许多用户连接-icode9专业技术文章分享
- 2024-10-31怎么在FreeBSD上 安装 OpenResty-icode9专业技术文章分享
- 2024-10-31运行 modprobe l2tp_ppp 时收到“module not found”消息提醒是什么-icode9专业技术文章分享
- 2024-10-31FreeBSD的下载命令有哪些-icode9专业技术文章分享