目录
(一)什么是const
constant在中文中翻译为常量,const是constant的形容词,翻译为恒定的,即常量所具有的特性。在c++中,const用来修饰一个变量,使其拥有一个恒定的值,不可以被改变。
(二)const修饰变量的属性
const修饰的变量仍然是变量而不是常数,遵循变量的特性-----如本地变量进入函数中才有,在离开函数后被清除,所以const修饰的本地变量在离开后也会被清除。
(三)const的用法简介
1)const修饰变量时,变量类型与const关键字的位置可随意调换
const int a = 0 ; //也可写作int const a = 0 ;
2)在定义const变量时必须进行初始化,除非在前面加上extern关键字变为声明,意思是告诉编译器存在这样一个const变量,不能被修改。
(四)const与指针的使用
1.const与指针
指针涉及到指针本身和指针所指向的东西,所以const与指针结合存在三种情况:
1)第一种是指针本身为const,即指针不能指向其他内存,因此不能进行指针的加减运算:
char * const q = "abc";//q is const
*q='c';//OK
q++;//ERROR
2)第二种是通过指针所指的东西是const,即不能通过指针修改它所指的变量的值,而不是指针指到哪里,哪里内存单元就变为const恒定的(此处较晦涩,需要梳理一下逻辑,const修饰指针所指的东西强调通过指针不能修改):
const char *p="ABCD";//(*p) is a const char
p++;//OK
*p='b';//ERROR
针对第二种情况,下面举两个例子:
例1:
#include<iostream>
using namespace std;
int main()
{
int a=1;
int const *p = &a;//指针p指向变量a
//(*p)++;//error:不能通过指针修改它所指的变量的值
a++;//通过其他途径修改了指针所指的变量的值
cout<<*p<<endl;
}
输出结果:
这里的p指向a,而const修饰p所指的东西,因此我们无法通过指针p修改a的值,也就是*p不能作为左值,但这并不代表p所指的内存是const那种无法修改的,我们可以直接去改变a的值,这是可行的。
例2:
const int ci = 0;
int *ip;
const int *cip;
ip=&ci; //Error:ci为const变量,其值不能修改,故不能将其地址传给一般指针
cip=&ci; //OK:指针指向const变量,可以将ci的地址传给指针
3)第三种并不常用,即用两个const分别修饰指针和指针所指向的东西
int i = 1;
const int* const p = &i;
2.const与字符常量:
在c语言中我们也遇到类似情况,使字符指针指向一个字符串常量,接着去修改某一位置的字符,但是运行输出hello world后会异常终止,代码如下:
#include<iostream>
using namespace std;
int main()
{
char *s = "hello world";
cout<<s<<endl;
s[0]='b';
cout<<s<<endl;
}
这是因为"hello world"是一个常量,被放在内存区的代码段中,而代码段不能被改写,若尝试改写,程序会终止,实际上定义的指针是指向const变量的:
const char *s = "hello world";
因此我们无法修改它的内容,如果想修改应该怎么做呢-----将const指针变为数组:
char s[] = "hello world";
整个数组在堆栈里面,因此要分配很大的空间,指针中"="的作用是将代码段中"hello world"的地址传给指针,在数组中的作用是把代码段中"hello world"拷贝到堆栈中,我们通过打印各自的地址来验证其在内存中的位置。
如果我们调用函数时,把整个对象传进去可能会耗费很大空间,如果传入一个地址进去会方便很多。当我们将对象的地址传入某些函数时,很可能对象的值被修改:
如下代码:
#include<iostream>
using namespace std;
void f(int *i)
{
(*i)++;
}
int main()
{
int p=3;
f(&p);
cout<<"p="<<p<<endl;
}
为了保护对象p的值不被函数修改,我们可以用const修饰对象起到保护的作用:
const int p = 3 ;
这样会阻止编译的通过,从而保护p的值不被改变。
(五)const与类的对象
1.const修饰对象
const修饰的对象里面的值不能被修改,但我们无法判断对象中的成员函数是否会更改对象内的某些数据,所以我们可以在某些成员函数中加入const:
const修饰成员函数的用法
1)在定义和声明中同时加上const关键字
2)不修改对象内数据的成员函数应该用const修饰
3)const修饰的成员函数对于const修饰的对象是安全可靠的
const修饰成员函数的原理
this指针指向的内容是const,即我们不能通过this指针来修改对象中的数据(this是class类型的指针)
2.const与函数重载:
成员函数中同名函数,其中一个用const修饰,可被认为是函数重载而非函数重名,代码如下:
#include<iostream>
using namespace std;
class A
{
int i;
public:
A():i(0) {}
void f()
{
cout<<"f()"<<endl;
}
void f()const
{
cout<<"f() const "<<endl;
}
};
int main()
{
const A a;
a.f();
return 0;
}
运行结果
可以被认为是函数重载是因为两个f函数的参数不同
void f(){...} //即void f(A* this)
void f()const{...} //即void f(const A* this)
3.const修饰成员变量
const修饰的成员变量必须在初始化列表中初始化