本文主要是介绍C++ const 全网最全总结(推荐),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
文章目录
- 前言
- 一、const 在普通变量中的应用
- 1、修饰内置类型
- 2、修饰指针类型
- i)常量指针
- ii)指针常量
- iii)常量指针常量
- 3、修饰引用类型
- 二、const 在函数中的应用
- 1、修饰函数传参
- i)内置类型参数
- ii)指针类型参数
- iii)引用类型参数
- 2、修饰函数返回值
- 三、const 在类中的应用
- 四、const 在 STL 中的应用
- 五、const 和 #define 的区别
- 六、突破 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 全网最全总结(推荐)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!