一、对变量的修饰

在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用法的简单总结的更多相关文章

  1. C++雾中风景3:const用法的小结

    const作为C与C++共有的关键字,很多使用的方式大同小异.但由于C++是一门面向对象的语言,在类和对象中有更多的使用规则.之前学习C语言的时候就被const这个关键字搅得焦头烂额,正巧也借这篇文章 ...

  2. static 与单例模式、auto_ptr与单例模式、const 用法小结、mutable修饰符

    一.static 与单例模式 单例模式也就是简单的一种设计模式,它需要: 保证一个类只有一个实例,并提供一个全局访问点 禁止拷贝  C++ Code  1 2 3 4 5 6 7 8 9 10 11 ...

  3. C++之常指针,指针常量,函数指针,const用法总结

    1.const char *p,char const *p,char * const p 对于C++而言,没有const * 修饰符,所以,const只可以修饰类型或者变量名.因而const char ...

  4. c++ const用法小结

    const用法 1,定义全局变量的内存分配问题 #define  Pi_1  3.14       //使用#define宏 const double Pi_2 = 3.14    //使用const ...

  5. const用法

    一.const作用 二.const用法 1.修饰一般常量   修饰符const可以用在类型说明符前,也可以用在类型说明符后. 例如: ; ; 2.修饰常数组  修饰符const可以用在类型说明符前,也 ...

  6. 【转】话说C语言const用法

    原文:话说C语言const用法 const在C语言中算是一个比较新的描述符,我们称之为常量修饰符,意即其所修饰的对象为常量(immutable). 我们来分情况看语法上它该如何被使用. 1.函数体内修 ...

  7. const用法详解(转)

    http://www.cnblogs.com/StudyRush/archive/2010/10/06/1844690.html 面向对象是C++的重要特性. 但是c++在c的基础上新增加的几点优化也 ...

  8. 【三支火把】---C语言const用法总结

    C语言关键字const相信对于不少C语言新手是既陌生又熟悉的,好像经常见,但是却不知道为何用,怎么用?学习至此,总结一下const的用法,使用程序来帮助你理解该关键字,希望能帮到像我一样的新手. 我看 ...

  9. typedef,static,const用法

    一.typedef主要功能是定义一个已存在类型的别名,但是和宏并存 宏与typedef区别 1.宏定义只是简单的字符串替换 2.typedef定义的类型是类型的别名,typedef后面是一个整体声明, ...

随机推荐

  1. Rabbitmq(三)

    1.在服务器安装好rabbitmq后,自己配置自己用的vhost,exchange和queue的绑定 2.项目添加RabbitMqClient.dll(nuget获取)引用 3.添加helper就可以 ...

  2. 帝国CMS给会员注册加入问答验证

    修改文件有e/enews/index.php //注册 elseif($enews=="register") { if($_POST['ask']=='帝国软件') { $user ...

  3. 生产环境rails console spring自动启动的问题

    在生产环境执行rails console没反应无法进入控制台,或者执行rails console的时候spring自动启动,导致所有的类名都无法识别,报错:NameError: uninitializ ...

  4. java int 与 Integer之间的区别

    int与integer的区别从大的方面来说就是基本数据类型与其包装类的区别: int 是基本类型,直接存数值,而integer是对象,用一个引用指向这个对象 1.Java 中的数据类型分为基本数据类型 ...

  5. 20155222 2016-2017-2 《Java程序设计》第4周学习总结

    20155222 2016-2017-2 <Java程序设计>第4周学习总结 教材学习内容总结 子类会继承父类的private成员,但是无法直接存取,必须通过父类提供的方法. 多态就是使用 ...

  6. 20155227 2016-2017-2 《Java程序设计》第一周学习总结

    20155227 2016-2017-2 <Java程序设计>第一周学习总结 教材学习内容总结 浏览教材,根据自己的理解每章提出一个问题 Java三个平台的区别. JDK.JRE.JVM区 ...

  7. HBase——使用Put迁移MySql数据到Hbase

    先上code: /** * 功能:迁移mysql上电池历史数据到hbase * Created by liuhuichao on 2016/12/6. */ public class MySqlToH ...

  8. 【LG3233】[HNOI2014]世界树

    题面 洛谷 题解 代码 #include <iostream> #include <cstdio> #include <cstdlib> #include < ...

  9. MySQL入门篇(二)之常见命令管理

    一.SQL结构化查询语言 SQL,英文全称Structured Query Language,中文意思是结构化查询语言.它是一种对关系数据库中的数据进行定义和操作的语言方法,是大多数关系数据库管理系统 ...

  10. angularjs 路由机制

    前言 AngularJS路由主要有内置的ngRoute和一个基于ngRoute开发的第三方路由模块ui-router,内置的ngRoute有时满足开发需求,使用ui-router可以解决很多原生ngR ...