C++:const用法的简单总结
一、对变量的修饰
在c++中,如果我们希望定义一个值不会被改变的变量,那么可以用关键字const对它进行修饰,被修饰后的变量其作用相当于一个常量
//这两种方式等价
2 语法1:const 类型名 变量名
3 语法2:类型名 const 变量名
特别注意:
1.const对象一旦创建,其值就不能再被改变。因此const对象必须初始化
const int i=get_size();//正确:运行时初始化
const int j=; //正确:编译时初始化
const int k; //错误:k是一个未经初始化的常量
2.在const对象上只能执行不改变其内容的操作
3.默认状态下,const对象被设定为仅在文件内有效。也就是说当多个文件中出现了同名的const变量时,其实等同于在不同文件中分别定义了独立的变量(如:file1中的const变量name和file2中的const变量name是两个不同的变量)
[注]:如果希望在多个文件之间共享const对象,则对于const变量不管是声明还是定义都必须添加extern关键字
//文件file1中
extern const int bufSize=;//定义并初始化一个常量,该常量能被其他文件访问
//文件file2中
extern const int bufSize; //与file1中定义的bufSize是同一个常量,这里extern的作用是指明bufSize并非本文件所独有,它的定义将在别处出现
二、对指针的修饰
A、底层const——指向常量的指针(常量指针)
指向常量的指针,顾名思义即指针指向的对象是一个常量,不能通过该指针对其所指向的对象进行修改
语法1:const 类型名 *变量名(推荐使用)
语法2:类型名 const *变量名
特别注意:
(1) 要想存放常量的地址,只能使用指向常量的指针
const double pi=3.14;//pi是一个常量,它的值不能被改变
double *pr=π//错误:ptr是一个普通的指针,不能用它指向一个常量
const double *cpr=π//正确:cpr是一个指向常量的指针
*cpr=; //错误:不能通过指向常量的指针对其所指的对象进行修改
(2)允许指向常量的指针指向一个非常量对象,但仍旧不允许其对所指向的对象进行修改
double value=12.5;//value是一个非常量对象
const double *ptr=&value;//允许指向常量的指针指向一个非常量对象
*ptr=13.5; //错误:不允许指向常量的指针对其所指向的对象进行修改,哪怕所指向的对象不是一个常量而是一个变量
[理解技巧]:所谓指向常量的指针不过是指针的“自己为是”,它以为自己指向的是常量,所以自觉的不改变所指对象的值(参考《C++ Primer》)
B、顶层const——指针常量
指针常量,即指针本身就是一个常量。
语法:类型名 *const 变量名
特变注意:
(1) 常量指针必须初始化,而且一旦初始化,则它的值(也就是存放在指针中的那个地址)就不能在改变。也就是说常量指针的指向不能够改变,只能一直指向其初始化的对象。
int value=;
int *const ptr=&value;//指针ptr是一个常量,它将一直指向变量value
(2) 指针本身是一个常量不代表不能通过该指针对其所指向的对象进行修改
int a=;
int *const ptr=&a;
*ptr=;//正确:运行通过常量指针对其所指向的对象进行就该
[理解技巧]:“从右向左”理解复杂const声明(参考《C++ Primer》)
const double *const ptr=π
•离ptr最近的符号是const,说明ptr本身是一个常量对象
•声明的下一个符号是*,说明ptr是一个常量指针
•之后的double说明指针ptr指向的对象是一个double类型的对象
•最后const说明指针ptr指向的对象还是一个常量对象
[注意]:更一般化来说,顶层const可以表示任意是常量的对象(适用于任何类型的数据),而底层const则与指针和引用等复合类型等基本类型部分有关
三、对引用的修饰
const引用,又称对常量的引用,顾名思义即为对const对象的应用
语法1:const 类型 &变量名(推荐)
语法2:类型 const &变量名
特别注意:
(1) 不能利用对常量的引用来修改其所绑定的对象
const int value=; //value是一个常量
const int &other_value=value;//正确:引用及其对应的对象都是常量
other_value=; //错误:oter_value是对常量的引用,不能通过其对所绑定的对象进行修改
int &value2=value; //错误:不允许让一个对非常量的引用来绑定一个常量,因为会有通过引用修改常量的风险
(2) 引用不是对象,而是别名。因此不存在引用是常量的情况(即不存在引用只能绑定在一个对象上恒定不变而无法改变绑定对象的情况)
(3) 初始化对常量的引用时允许用任意表达式作为初始值,只要该表达式的结果能转换成引用了的类型即可
const int r=;
const int &value=r*+;//正确
(4) 允许一个对常量的引用绑定一个非常量的对象、字面值、甚至是一个一般表达式
int re=;
const int &value=re;//正确:允许一个对常量的引用绑定一个非常量对象
const int &value2=;//正确:允许一个对常量的引用绑定一个字面值
const int &value3=re*+;//正确:允许一个对常量的引用绑定一个任意表达式
int &value4=re; //错误:不允许一个对非常量的引用绑定一个常量对象
[理解]:将一个对常量的引用绑定在一个非常量对象的过程
编译器将语句:
double value=3.14;
const double &r=value;
转化为:
double value=3.14;
const double temp=value;//由双精度浮点数生成一个临时的double常量temp
const double &r=temp;//让r绑定这个临时的double常量temp
[理解技巧]:所谓指向常量的引用不过是引用的“自己为是”,它以为自己绑定的是常量,所以自觉的不改变所绑定对象的值(参考《C++ Primer》)
四、对函数参数的修饰
用const修饰的函数参数,表示其在函数内是不允许被改变的
void function(const int a){
a=;//错误:a是常量,在函数内部不允许对其进行修改
}
特别注意:
(1) 顶层const作用于对象本身,当用实参初始化函数的形参时会忽略掉顶层const,换句话说也就是当形参由顶层const时,传给它常量对象还是非常量对象都是可以的。
void fcn(const int i){/*fcn能够读取变量i,但函数不允许修改它*/}
void fcn(int i){} //错误:由于顶层const被忽略了,因此不算对函数fcn进行了重载
(2) 尽量使用对常量的引用
•把函数不允许改变的形参定义成普通的引用会给函数的调用者一种“函数允许修改它的实参值”的错觉
•使用普通引用会限制函数所能接受的实参类型。比如const对象、字面值等无法传递给普通的形参变量;而对常量的引用不仅可以接受常量对象,还可以接受非常量对象
void func(const int &value){}//尽量使用对常量的引用
五、对函数返回值的修饰
用const修饰函数返回值的含义和用const修饰普通变量以及指针的含义基本相同,表示函数的返回值是一个常量。
const int function1()//没有太大的意义
const int *function2() //调用时:const int*ptr=function2();
//可以把function2()看成一个变量,即返回一个指向常量的指针
int* const function3() //调用时:int *const ptr=function3();
//可以吧function3()看成一个变量,即返回一个是常量的指针
六、对类成员变量的修饰
const修饰类的成员变量,表示其为成员常量,不能够被修改。
特别注意:
使用const修饰的成员变量,只能在类的构造函数的初始化列表中赋值,不能在类的构造函数的函数体内赋值
class Student{
private:
const string m_Name;//成员常量,不能够被修改
.......
public:
Student(string name):m_Name(name){ //正确,只能在构造函数的初始化列表中赋值
m_Name=name; //错误,不允许在构造函数的函数体内对成员常量进行赋值
......
}
}
七、对类成员函数的修饰
const修饰类的成员函数,表示在该成员函数体内不允许改变该类对象的任何成员变量,同时也不允许在该成员函数体内调用任何非const成员函数。通常定义时将关键字const写在函数参数列表之后。
class Student{
private:
const long long id;//成员常量
string name;
int age;
public:
void function1();
void function2() const;//声明一个常成员函数
void functon3() const{ //定义一个常成员函数
function1(); //错误:常成员函数中不允许调用非const成员函数
function2();//正确:常成员函数中允许调用const成员函数
age=; //错误:常成员函数中不允许修改该类对象的任何成员变量或成员常量
return name;//正确:在不改变成员变量的前提下,运行引用成员变量或成员常量
}
}
特别注意:
常成员函数中的const关键字,其主要作用是用来修改隐式this指针的类型(this指针详见http://www.cnblogs.com/duwenxing/p/7410687.html)。默认情况下,this的类型是指向类类型非常量版本的常量指针(即指针本身是常量,当其指向的对象不是常量)。如上例中Student类中的普通成员函数的this指针的类型是 Student *cosnt;而常成员函数的this指针由于在其参数列表后添加了关键字const,故其的this指针的类型是const Student *const,也就是说此时this指针指向的是一个常量,因此常成员函数中不能修改类中的任何成员变量(在常成员函数中修改成员变量相当于先将成员变量赋值给一个常量,然后再对常量进行修改,因此是不允许的),也不能调用任何非const成员数(有修改类中成员变量的企图)。
[注意]:类中可以利用const对类中的成员函数进行重载
class Student{
public:
void function(){}
void function() const {}//对成员函数进行重载
}
八、对类对象/对象指针/对象引用的修饰
•const修饰的类对象表示该对象为常量对象,也就是说该对象中的任何成员都不能被修改。(对象指针/对象引用类似)
•const修饰的对象不能调用该对象的任何非const成员函数,因为任何非cosnt成员函数都会有修改该对象成员变量的企图
class Student{
public:
void functionA(){}
void function() const {}
} int main(){
const Student stu1;//stu1是一个常量对象
stu1.functionA(); //错误:常量对象不允许调用它的非const成员方法
stu1.functionB();//正确:常量对象只允许调用它的const成员方法 const Student * stu2=new Student();
stu2->functionA();//错误
stu2->fucntionB();//正确
}
九、const_cast
const_cast能够改变表达式的常量属性,但它只能改变运算对象的底层const,即:
•能够将常量指针转化为非常量指针,并且仍然直线原来的对象
•能够将对常量的引用转化为对非常量的引用,并且仍然绑定原来的对象
•能够将常量对象转化为非常量对象
语法:const_cast<type_id>(expression)
(具体见 http://www.cnblogs.com/duwenxing/p/7406043.html)
十、const与宏定义
• const常量有数据类型,而宏定义没有数据类型
• 编译器对const常量会进行类型安全检查;而对宏定义则只是进行字符替换,没有类型安全检查,甚至宏定义在字符替换时可能会产生意料不到的错误
• 从汇编角度来说,const常量给出的是对应的内存地址,而宏定义给出的则是立即数。因此const定义的常量在程序运行过程中只有一份拷贝,而宏定义的常量在内存中有若干拷贝
特别注意:
编译器通常不为const常量分配存储空间,而是将它们保存在符号表中,这使得其成为一个编译期间的常量,由于没有了存储于读内存的操作,故使得其的效率很高
#define VALUE 2017 //宏定义
const int VALUE=;//const常量
C++:const用法的简单总结的更多相关文章
- C++雾中风景3:const用法的小结
const作为C与C++共有的关键字,很多使用的方式大同小异.但由于C++是一门面向对象的语言,在类和对象中有更多的使用规则.之前学习C语言的时候就被const这个关键字搅得焦头烂额,正巧也借这篇文章 ...
- static 与单例模式、auto_ptr与单例模式、const 用法小结、mutable修饰符
一.static 与单例模式 单例模式也就是简单的一种设计模式,它需要: 保证一个类只有一个实例,并提供一个全局访问点 禁止拷贝 C++ Code 1 2 3 4 5 6 7 8 9 10 11 ...
- C++之常指针,指针常量,函数指针,const用法总结
1.const char *p,char const *p,char * const p 对于C++而言,没有const * 修饰符,所以,const只可以修饰类型或者变量名.因而const char ...
- c++ const用法小结
const用法 1,定义全局变量的内存分配问题 #define Pi_1 3.14 //使用#define宏 const double Pi_2 = 3.14 //使用const ...
- const用法
一.const作用 二.const用法 1.修饰一般常量 修饰符const可以用在类型说明符前,也可以用在类型说明符后. 例如: ; ; 2.修饰常数组 修饰符const可以用在类型说明符前,也 ...
- 【转】话说C语言const用法
原文:话说C语言const用法 const在C语言中算是一个比较新的描述符,我们称之为常量修饰符,意即其所修饰的对象为常量(immutable). 我们来分情况看语法上它该如何被使用. 1.函数体内修 ...
- const用法详解(转)
http://www.cnblogs.com/StudyRush/archive/2010/10/06/1844690.html 面向对象是C++的重要特性. 但是c++在c的基础上新增加的几点优化也 ...
- 【三支火把】---C语言const用法总结
C语言关键字const相信对于不少C语言新手是既陌生又熟悉的,好像经常见,但是却不知道为何用,怎么用?学习至此,总结一下const的用法,使用程序来帮助你理解该关键字,希望能帮到像我一样的新手. 我看 ...
- typedef,static,const用法
一.typedef主要功能是定义一个已存在类型的别名,但是和宏并存 宏与typedef区别 1.宏定义只是简单的字符串替换 2.typedef定义的类型是类型的别名,typedef后面是一个整体声明, ...
随机推荐
- MySQL->AUTO_INCREMENT[20180516]
MySQL表格中自增长主键AUTO_INCREMENT使用,实现序列的最简单的方式 创建一个AUTO_INCREMENT自增的表 mysql> create table seq_test( ...
- 利用Git Bash 远程访问服务器
首先 先在自己的当前主机打开git bash ssh-keygen 生成密钥对 (默认就好,我自己是一直摁着回车的) cat ~/.ssh/id_rsa.pub 查看生成好的公钥,并复制好 打开你远端 ...
- Redis底层数据类型
Redis主要数据结构:简单动态字符串(SDS).双端链表.字典.跳跃表.整数集合.压缩列表和快速列表: 一.简单动态字符串(SDS): Redis没有直接使用C语言中的传统的字节数组保存字符串,而是 ...
- 记一次学习PHP中的错误
今天学习PHP时,回想起一段代码 <?php> $i = true; $o = true; $p = false; if($i or $o and $p){ echo '输出为'.'tru ...
- C++ —— 非类中使用const定义常量的初始化,以及#define和typedef的区别
总结一下在非类中使用const关键字定义常量时的初始化问题,亲测VS2015.顺便记录#define宏和typedef的区别. 1 首先对const声明的常量的初始化做简单小结: , w2 = , w ...
- 二叉树 ADT接口 遍历算法 常规运算
BTree.h (结构定义, 基本操作, 遍历) #define MS 10 typedef struct BTreeNode{ char data; struct BTreeNode * lef ...
- ubuntu 和windows 分别在anaconda上安装tensorflow
windows下 的anaconda安装tensorflow: 在Anaconda Prompt中:conda install tensorflow python=3.5一直下载失败.总结一下原因可能 ...
- 5.18-笨办法学python-习题15(open等读取文件)
from sys import argv script,filename=argv #不要忘了script(相当于一个固定变量),filename(可变变量) txt=open(filename) # ...
- java入门---循环结构 - for, while 及 do...while&break&continue
顺序结构的程序语句只能被执行一次.如果您想要同样的操作执行多次,,就需要使用循环结构.Java中有三种主要的循环结构: while 循环 do…while 循环 for 循环 在Jav ...
- 新技能get,使用PHPStorm的deployment工具
1. 工具栏 Tools - Deployment - Configuration 2. 添加一个服务端的配置信息 type 类型可以选择:FTP.local等. 填完信息别忘了点"Test ...