C++中的const

一、const变量

定义一个变量为const,也就是常量,说明这个这个量是不可修改的,既然不可修改,就说明在定义的时候就要初始化。初始化可以用常量初始化,也可以用普通的变量初始化。例如:

const int val = 10;
int tmp = 20;
const int val2 = tmp;
cosnt变量的存储以及作用域,先看一段代码:

#include <iostream>
using namespace std;

int n = 0;
const int totalVal = 10;

void func()
{
     int tmp;
     const int count = 10;
     cout<<"count = "<<count<<" and address = "<<&count<<" and tmp address = "<<&tmp<<endl;
}

int main()
{
    const int kk = 20;
    int m = 2;
    cout<<"Address of n = "<<&n<<endl;
    cout<<"Address of totalval = "<<&totalVal<<endl;
    cout<<"Address of kk = "<<&kk<<endl;
    func();
    func();
    cout<<"Address of m = "<<&m<<endl;
    return 0;
}
运行结果:

Address of n = 0x443010
Address of totalval = 0x44007c
Address of kk = 0x22ff74
count = 10 and address = 0x22ff40 and tmp address = 0x22ff44
count = 10 and address = 0x22ff40 and tmp address = 0x22ff44
Address of m = 0x22ff70

可以看到,n、totalVal在一个存储区域(全局变量区),而func中的count和tmp以及main()中的m、kk在一个区域(栈区),我们暂时可以推测,const变量的存储和访问特点与普通的变量没有太大区别。

修改一下代码实验一下:

#include <iostream>
using namespace std;

int n = 0;
const int totalVal = 10;

const int * func()
{
     int tmp;
     const int count = 10;
     cout<<"count = "<<count<<" and address = "<<&count<<" and tmp address = "<<&tmp<<endl;
     const int *p = &count;
     return p;
}

void f()
{
     int tmp = 0;
     cout<<"Address of tmp = "<<&tmp<<endl;   
}

int main()
{
    const int kk = 20;
    int m = 2;
    cout<<"Address of n = "<<&n<<endl;
    cout<<"Address of totalval = "<<&totalVal<<endl;
    cout<<"Address of kk = "<<&kk<<endl;
    cout<<"Address of m = "<<&m<<endl;
    const int *p = func();
    cout<<"p1 = "<<p<<" value = "<<*p<<endl;
    f();
    f();
    cout<<"p2 = "<<p<<" value = "<<*p<<endl; 
    return 0;
}
结果是:

Address of n = 0x443010
Address of totalval = 0x4400a4
Address of kk = 0x22ff74
Address of m = 0x22ff70
count = 10 and address = 0x22ff40 and tmp address = 0x22ff44
p1 = 0x22ff40 value = 2088763392
Address of tmp = 0x22ff44
Address of tmp = 0x22ff44
p2 = 0x22ff40 value = 2088763392

可以看出,当函数执行完了以后,原来func中存放count的空间被释放了。确实是存放在栈区。因此,const变量的存储和作用域与普通变量相同。但是有一点特别,普通变量声明为全局变量的时,外部文件可以直接通过extern调用。而const全局变量默认为文件的局部变量,也是就只有文件内部可访问,外部无法访问,如果要外部文件可访问,需要在定义const全局变量时候使用extern关键字。

例如:

在file1.cpp中如下定义和初始化

extern const int  val = 10;

在file2.cpp中才能调用:

extern const int val;


2.const引用
指向const对象的引用。

const int val = 10;

const int &reVal = val;

const对象不能使用非const引用指向。

例如:int &reVal2 = val;  就是错误的

const引用可以指向非const对象。

使用const引用的作用在于,可以通过引用读取对象,但是不能通过引用修改对象。但对象本身可能可以通过其他方式修改,见代码:

#include <iostream>
using namespace std;

int main()
{
    const int conVal = 10;
    int tmpVal = 5;
    const int &conRe = conVal;
    const int &tmpRe = tmpVal;
    cout<<conVal<<" "<<conRe<<endl;
    cout<<tmpVal<<" "<<tmpRe<<endl;
    tmpVal = 20;
    cout<<tmpVal<<" "<<tmpRe<<endl;
    system("pause");  
    return 0;
}
结果:

10 10
5 5
20 20

可以看出,tmpVal可以由一个const引用tmpRe指向,但其值仍然是可以修改的。但是,如果在程序中使用tmpRe修改,就会报错,例如:tmpRe = 20;编译错误。

const引用有什么用处呢?我们都知道引用的作用就是不需要复制,特别是在函数传参的时候,可以提高效率,所以我们往往会使用类似void func(int &re)这样的函数原型,但是这里有个问题,如果我们想让re只读呢?那就要用高const引用了。定义这样的函数原型void func(cosnt int &re),这样,即免去了函数调用的传值消耗,也防止了参数本身被修改,又由于const引用可以指向非cosnt对象,因此,这样的原型对于非const的实参也是适用的。


3.const指针

const指针分为:指向const对象的指针,指向对象的const指针;指向const对象的const指针。下面看一段代码来了解这三种用法:

#include <iostream>
using namespace std;

int main()
{
    const int conVal = 10;
    const int conVal2 = 100;
    int tmpVal = 20;
    int tmpVal2 = 200;
    const int *p1 = &conVal;        //指向const对象的指针,指向了一个const对象 
//    int *const p2 = &conVal;      error,指向普通对象的const指针,指向了一个cosnt对象 

    const int *p3 = &tmpVal;        //指向cosnt对象的指针,指向了一个普通对象 
    int *const p4 = &tmpVal;        //指向普通对象的cosnt指针,指向了一个普通对象 

    const int *const p5 = &conVal;   //指向const对象的const指针,指向了一个const对象 
    const int *const p6 = &tmpVal;   //指向const对象的const指针,指向了一个普通对象 

    cout<<*p1<<endl;
//    *p1 = 1;          error,不能通过p1修改指向对象的值 
    p1 = &conVal2;      //更改指针指向对象 
    cout<<*p1<<endl;    //现在输出的是conVal2的值 

    cout<<*p3<<endl;    
//    *p3 = 3;          error,不能通过p3修改对象的值  
    
    cout<<*p4<<endl;
    *p4 = 4;            //通过指针p4修改conVal的值 
    cout<<*p4<<endl;
//    p4 = &conVal;    error,不能修改p4的指向   

    cout<<*p5<<endl;
//    *p5 = 5;         error,不能修改指向对象的值 
//    p5 = &conVal2;   error,不能更改指针指向  
    
    cout<<*p6<<endl;
//    *p6 = 6;         rror,不能修改指向对象的值 
//    p6 = &tmpVal2;   error,不能更改指针指向
  
    system("pause");  
    return 0;
}

通过程序看:

(1)指向const对象的指针

这里的p1和p3都是这种指针,可以看到,指向cosnt对象的指针即可以指向const对象,也可以指向非const对象,这点与cosnt引用相同,不同的值,指向const对象的指针,可以更改其指向,这里p1就从原来指向conVal改成了指向conVal2,但是,不能通过p1和p3来修改所指向对象的内容。原因:指向const对象的指针,因为指向的是const对象,因此,不能修改对象内容,而const只限定了指向的对象为const,并没有限定指针本身为const,因此,指针本身可以更改自己的指向。指向const对象的指针还有一种声明格式:int const *p = conVal;这个和p1以及p3的声明是等价的。


(2)指向普通对象的const指针

这里的p2和p4都是这样的指针,可以看出,由于指针本身是指向非const对象的,因此,可以通过指针来修改指向对象的值,下面的p4就修改了tmpVal的值。如果用这种指针去指向了一个const对象,编译器将报错,因为cosnt对象不能修改,而用这种指针指向后便可以修改,这样将产生严重的安全问题,p2说明了这种用法是不可行的。由于是一个const指针,因此限定了指针本身是一个常量,因此就当指针指向一个对象之后,将不能再改变其指向,它将一直指向该对象。因此,指向普通对象的const指针必须在声明时初始化其指向。


(3)指向const对象的constt指针

包括了上面提到的两种限制,限制最严格。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值