const限定符全解
一、const 修饰普通变量
int const a = 500;
const int a = 600;
上述两种情况相同,都是声明一个const型的变量,它们的含义是:变量a的值不可改变!
二、const 修饰 指针
int b = 500;
const int * a = &b; //情况1
int const * a = &b; //情况2
int * const a = &b; //情况3
const int * const a = &b; //情况4
这四种情况,先来分析前三种。第四种是上面三种的一个组合,最后分析。
针对情况1、2、3 其实只是两类情况:在星号左边还是在星号右边。在星号左边则const修饰的是指针所指向的变量,即指针指向为常量;如果是在星号右边,const修饰的是指针本身,即指针本身是常量。下面具体分析一下。
情况1和情况2中const都是位于星号的左侧,情况相同,可以归为一类,都是指针所指向的内容为常量(与const放在变量声明符的位置无关),这种情况下不允许对内容进行更改操作。
针对情况1和情况2的变量声明,我们可以看如下情况:
(1) *a = 600;//错误,指针所指内容为常量!
(2) b = 700; //此时*a 的值就是700了
(3) int c = 800; a = &c; //此时*a变成了800了
从上面(1)、(2)、(3)三种情况来看,情况1、情况2这种变量声明方式的意思在于:不能通过a指针来修改a指针所指地址中存放的内容,但是可以通过修改指针所指向的地址。
如图所示,声明变量时a指向0x00000000,其值是500。我们不同通过操作*a来改变0x00000000里面所存的值。但是我们可以改变a指针所指向的地址,比如将a指向0x00000004或者其它地址。也可以新定义一个变量来改变0x00000000里面的值,但是就是不能通过a指针来改变里面存的值。
在情况1、情况2下const int *a;可以在声明的时候不初始化
再来看一下情况3,情况3是指针为常量,也就是说a只能指向0x00000000这个地址。
*a = 600; 在情况3是正确的,它可以通过*a来操控这个地址中所存内容,但是不能改变a指针所指向的地址。
情况3其实还有一种写法:const (int *) a = &b; 因为在声明变量后无法再修改a指针所指向的地址,因此必须在声明的时候初始化
现在再来看看情况4,情况四星号左右两边都有const,也就是说它即是常指针(指针所指向的地址不能变更),其指向的内容也不能通过该指针进行修改。
两个判断对错题:
const int *a = new int;
int * b = a;
错误,因为声明指针的目的是为了对其指向的内容 进行改变,而声明的指针e指向的是一个常量,所以不正确;
int * const a = new int;
int *b = a;
正确,因为声明指针所指向的内容可变;
三、const 修饰函数
(1)参数为指针
void function (const int a); //情况1
void function (const int * a); //情况2
void function (int const * a); //情况3
void function (int * const a); //情况4
情况1:传递过来的参数a在函数中不能被修改(无意义,因为本身就是形参,改不改都不会影响实参)
情况2与情况3相同:a指针所指的内容*a 不能修改
情况4:指针a为常量,其地址不能改动,但是*a可以修改(无意义,改不改a指针指向的地址都不影响实参)
(2)参数为引用
void function (const class & a); //情况1
void function (const int & a); //情况2
情况1:在函数内不能改变类对象a,a的成员变量的值也不能被修改
情况2:function()函数不能修改a,对a是只读的
这样的一个const引用传递和最普通的函数按值传递的效果是一模一样的,他禁止对引用的对象的一切修改,唯一不同的是按值传递会先建立一个类对象的副本,然后传递过去,而它直接传递地址,所以这种传递比按值传递更有效。另外只有引用的const传递可以传递一个临时对象,因为临时对象都是const属性,且是不可见的,他短时间存在一个局部域中,所以不能使用指针,只有引用的const传递能够捕捉到这个家伙。
(3)const 修饰函数返回值
const 修饰函数返回值其实用的并不是很多,他的含义和const修饰普通变量以及指针含义基本相同。
const int function(); //情况1
const int * function(); //情况2
int * const function(); //情况3
情况1:毫无意义,参数返回本身就是赋值,赋值加个const对被赋值的变量无影响。
情况2:调用时 const int * pvalue = function(); 我们可以将function()看成一个变量,那么就是我们前面说的const修饰指针的情况了。此时指针的内容是不能被该指针修改的。
情况3:调用时 int * const pvalue = function(); 同样可以将function()看成一个变量,那么也就是const修饰指针的情况了。
一般情况下,函数的返回值为某个对象时,如果将其声明为const时,多用于操作符的重载。
通常,不建议用const修饰函数的返回值类型为某个对象或对某个对象引用的情况,原因如下:如果返回值是某个对象并且为const(const A test = A 实例)或返回某个对象的引用为const(const A& test = A实例),则返回值具有const属性,则返回实例只能访问类A中的公有(保护)数据成员和const成员函数,并且不允许对其进行赋值操作,这在一般情况下很少用到。
四、类中const的使用
(1) const修饰成员函数、成员变量
class point{
private:
int x;
int y;
const int c; // 成员常量不能被修改
public:
point(int a=0):c(a) { }; //成员常量在初始化列表中赋值
int get_x() const; //类内声明
};
int point :: get_value() const //类外定义,注意const不能省!
{
return x;
}
const 成员函数可以访问类中的所有成员变量(const或非const成员变量),但是都不能修改任何一成成员;
const 成员函数只能调用类中的const成员函数,而不能调用类中的非const成员函数;
如果在非const成员函数中,this指针指示一个类类型的;
如果在const成员函数中,this指针式一个const类类型的;
如果在volatile成员函数中,this指针就是一个volatile类类型的。
数据成员
非const成员函数
const成员函数
非const的数据成员
可以访问,也可以修改值
允许访问,但不能修改值
const数据成员
可以访问,也可以修改值
允许访问,但不能修改值
const对象的数据成员
不允许访问
允许访问,但不能修改值
常数据成员是不能被赋值的!初始化类内部的常量的两种方法
一种方法就是static和const并用,在外部初始化:
class A
{
public:
A(){}
private:
static const int i;
};
const int A :: i =3;
另一种很常见的方法就是初始化列表:
class A
{
public:
A (int i =0): test (i) { }
private:
const int test;
};
(2)指向对象的常指针
Point a,b;
Point * const p = &a;
P = &b; //错误,p指针声明并赋值后便不能再修改其指向的地址了
(3)指向常对象的指针变量
Point a;
Point const * p;
p = &a;
p指针指向的内容*p不能被p指针修改,p->x= 19;类似的语句在这种情况下就是错误的。
对于const类对象/指针/引用,只能调用类的const成员函数,因此,const修饰成员函数的最重要作用就是限制对于const对象的使用。
(4) const修饰类对象/对象指针/对象引用
· const修饰类对象表示该对象为常量对象,其中的任何成员都不能被修改。对于对象指针和对象引用也是一样。
· const修饰的对象,只能调用该对象的const成员函数,该对象的任何非const成员函数都不能被调用(除了由系统自动调用的隐式构造函数和析构函数),因为任何非const成员函数会有修改成员变量的企图。
示例:
class AAA
{
void func1( );
void func2( ) const;
}
const AAA aObj;
aObj.func1( ); 错误
aObj.func2( ); 正确
const AAA* aObj = new AAA();
aObj-> func1( ); 错误
aObj-> func2( ); 正确
一道思考题:
以下定义的赋值操作符重载函数可以吗?
class A
{
const A& operator=(const A& a); //赋值函数
}
A a,b,c:
(a=b)=c;
a = b= c;
(a=b)=c; 错误,在const A::operator=(const A& a)中,参数列表中的const的用法正确,而当这样连续赋值的时侯,问题就出现了:因为a.operator=(b)的返回值是对a的const引用,不能再将c赋值给const常量。
a = b= c; 正确!
五、const常量与define宏定义的区别
Point a;
(1)编译器处理方式不同
define宏是在预处理阶段展开
const常量是在编译运行阶段使用
(2)类型和安全检查不同
define宏没有类型,不做任何类型检查,仅仅是展开
const常量有具体的类型,在编译阶段会执行类型检查
(3)存储方式不同
define宏仅仅是展开,有多少地方使用,就展开多少次,不会分配内存
const常量会在内存中分配(可以是堆中,也可以是栈中)
六、将const类型转换为非const类型的方法
采用const_cast 进行转换。
用法:const_cast (expression)
该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外, type_id和expression的类型是一样的。
· 常量指针被转化成非常量指针,并且仍然指向原来的对象;
· 常量引用被转换成非常量引用,并且仍然指向原来的对象;
· 常量对象被转换成非常量对象。
示例:
#include
using namespace std;
const int * find( int val, const int *t, int n);
int main()
{
int a[ ] = {2, 4, 6};
int * ptr;
ptr = const_cast(find(4, a, 3));
if(ptr == 0)
cout<<"not found\n";
else
cout<<"found; value = " <<*ptr <<‘\n‘;
return 0;
}
const int * find( int val, const int * t, int n)
{
int i;
for( i=0; i
if( t[i] == val)
return &t[i];
return 0; // not found
}
七、使用const的一些建议
1、要大胆的使用const,这将给你带来无尽的益处,但前提是你必须搞清楚原委;
2、要避免最一般的赋值操作错误,如将const变量赋值,具体可见思考题;
3、在参数中使用const应该使用引用或指针,而不是一般的对象实例,原因同上;
4、const在成员函数中的三种用法要很好的使用;
5、不要轻易的将函数的返回值类型定为const;
6、除了重载操作符外一般不要将返回值类型定为对某个对象的const引用。
C++ const限定符全解,,
C++ const限定符全解
推荐阅读
权限管理包含三部分:访问页面的权限,操作功能的权限和获取数据权限。页面权限:登录用户所属角色的可访问页面的权限功能权限:登录用户所属角色的可访问页面的操作权限数据权限:登录用户所属 ...
[详细]
蜡笔小新 2024-11-23 16:30:15
本文介绍了一个来自AIZU ONLINE JUDGE平台的问题,即清洁机器人2.0。该问题来源于某次编程竞赛,涉及复杂的算法逻辑与实现技巧。 ...
[详细]
蜡笔小新 2024-11-23 17:16:33
本文由chszs撰写,详细介绍了Apache Mina框架的核心开发流程及自定义协议处理方法。文章涵盖从创建IoService实例到协议编解码的具体步骤,适合希望深入了解Mina框架应用的开发者。 ...
[详细]
蜡笔小新 2024-11-23 15:02:21
汇总了2023年7月7日最新的网络安全新闻和技术更新,包括最新的漏洞披露、工具发布及安全事件。 ...
[详细]
蜡笔小新 2024-11-23 13:35:48
本文提供了一个关于AC自动机(Aho-Corasick Algorithm)的详细解析与实现方法,特别针对P3796题目进行了深入探讨。文章不仅涵盖了AC自动机的基本概念,还重点讲解了如何通过构建失败指针(fail pointer)来提高字符串匹配效率。 ...
[详细]
蜡笔小新 2024-11-23 13:17:52
本报告记录了嵌入式软件设计课程中的第二次实验,主要探讨了使用KEIL V5开发环境和ST固件库进行GPIO控制及按键响应编程的方法。通过实际操作,加深了对嵌入式系统硬件接口编程的理解。 ...
[详细]
蜡笔小新 2024-11-23 13:00:00
本文详细解析了LeetCode第102题——二叉树的层次遍历问题,提供了C++语言的实现代码,并对算法的核心思想和具体步骤进行了深入讲解。 ...
[详细]
蜡笔小新 2024-11-23 12:14:28
在游戏开发中,音频播放是提升玩家沉浸感的关键因素之一。本文将探讨如何在Unity3D中高效地管理和播放不同类型的游戏音频,包括背景音乐和效果音效,并介绍实现这些功能的具体步骤。 ...
[详细]
蜡笔小新 2024-11-22 21:05:22
本文探讨了一种常见的C++面试题目——实现自己的String类。通过此过程,不仅能够检验开发者对C++基础知识的掌握程度,还能加深对其高级特性的理解。文章详细介绍了如何实现基本的功能,如构造函数、析构函数、拷贝构造函数及赋值运算符重载等。 ...
[详细]
蜡笔小新 2024-11-22 19:21:22
本文探讨了开发者如何更有效地学习鸿蒙操作系统,提供了来自行业专家的建议,包括系统化学习方法、职业规划建议以及具体的开发技巧。 ...
[详细]
蜡笔小新 2024-11-23 19:22:14
本文详细介绍了在 JavaScript 编程中如何处理引号的多级嵌套问题,包括双引号、单引号以及转义字符的正确使用方法。 ...
[详细]
蜡笔小新 2024-11-23 11:47:34
本文探讨了使用Python实现监控信息收集的方法,涵盖从基础的日志记录到复杂的系统运维解决方案,旨在帮助开发者和运维人员提升工作效率。 ...
[详细]
蜡笔小新 2024-11-23 11:25:14
本文介绍了一种有效的方法来解决在使用UIScrollView时出现的自动向下偏移的问题,通过调整特定的属性设置,可以确保滚动视图正常显示。 ...
[详细]
蜡笔小新 2024-11-23 11:01:29
本文介绍了在控制器中返回JSON结果的方法,并详细说明了如何利用jQuery处理和展示这些数据,为Web开发提供了实用的技巧。 ...
[详细]
蜡笔小新 2024-11-23 10:41:31
Awk是一款功能强大的文本分析与处理工具,尤其在数据解析和报告生成方面表现突出。它通过读取由换行符分隔的记录,并按照指定的字段分隔符来划分和处理这些记录,从而实现复杂的数据操作。 ...
[详细]
蜡笔小新 2024-11-23 09:44:24