打印
[手机平台]

C++中的const

[复制链接]
956|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zzx__|  楼主 | 2013-11-21 18:09 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
const修饰变量

还是先从C谈起吧,在学习C语言的时候就知道const修饰的是常量,其值是不可改变的,真的是这样吗?

[cpp] view plaincopyprint?
int main()  
{  
   const int a  = 1;  
   int *b = (int *)&a;  
   *b = 2;  
  printf("a = %d\n",a);  
  return 0;  
}  
结果是2,但是a = 2则会报错,表明在C中const修饰的只是只读变量,本质上是可以被修改的!那么在C++里面呢?稍微修改一下上面的代码。
[cpp] view plaincopyprint?
int main()  
{  
   const int a  = 1;  
   int *b = (int *)&a;  
   *b = 2;  
  printf("a = %d\n",a);  
  printf("*b = %d\n",*b);  
  printf("&a = %0x\n",&a);  
  printf("&a = %0x",b);  
  return 0;  
}  

咋一看,很奇怪的结果啊b与&a的值明明是一样的,怎么对其取值却不同呢?其实在C++中const才成为了真正的常量,对const修饰的变量不会为其分配内存空间,每次取用其时都会用符号表里面的值直接替换,但是为了兼容c语言在程序中有&a时还是会为其分配内存空间(当const常量为全局变量并需要在其他文件中引用或对其使用&取地址时会为其分配内存空间)。

由上可见在C++中const修饰的变量类似于宏定义,区别是:

const常量是由编译器处理的,提供类型检查和作用域检查;
宏定义由预处理器处理,单纯的文本替换
另外默认情况下C中的const是外联的,C++中时内联的,因此在C++中若要使用其他文件中定义的const常量则必须使用extern关键字。

该节的最后再介绍一下const退化。

[cpp] view plaincopyprint?
int main()  
{  
    int temp = 1;  
    const int b = temp;  
    volatile const int c = temp;  
    int *a1 = (int *)&b;  
    int *a2 = (int *)&c;  
    *a1 = 2;  
    *a2 = 3;  
    cout<<b<<endl;  
    cout<<c<<endl;  
    cin.get();  
    return 0;  
}  
从输出结果来看这里的const常量b,和c貌似和前面提到的C中的const常量一样,退化为了只读变量,这里解释一下,使用volaitle之后,该变量使用时每次都从内存中取值,故其退化为只读变量,对于变量b由于在编译期间不能直接确定其值故也退化为了只读变量!
const修饰指针

这里没什么好说的,左数右指,const在*左边,a指向的内容不可修改,右边指针本身不可被修改。
[cpp] view plaincopyprint?
const int *a;       <span style="white-space:pre">  </span>  
int const *a;         //*a不可改变  
int *const a;        //a不可变,需在定义的时候初始化  
const int *const a;  //a及*a均不可变,需在定义的时候初始化  
const引用

这里只是简单介绍一下,下面会有更详细的说明
[cpp] view plaincopyprint?
int main()  
{  
    const int &a = 1;   //这里会为1分配内存空间,&指向这片内存空间  
    int *b = (int *)&a; //  
    *b = 2;  
    cout<<a<<endl;  
  return 0;  
}  

先不管引用在编译器内部的实现(int &p ==const int *p)我们在使用的时候把他当成别名就可以了。有了上面的解释相信最后打印出2的结果也就不难理解了。
下面继续,看一下两段小程序
[cpp] view plaincopyprint?
const int a = 1;  
int &b = a;  
  
int a = 1;  
const int &b = a;  

编译后发现第一段是错误的,这个是很好理解的,非const的引用怎么能用const变量初始化呢,那么下面的呢?
[cpp] view plaincopyprint?
float a = 1.0;  
int &b = a;  
结果是编译不通过,但是如果改为const int &b = a;编译就可以通过了,比较奇怪?考虑其在编译器中的实现,以上代码翻译为
[cpp] view plaincopyprint?
float a = 1.0;  
int temp = a;  
int &b = temp;  

那么对b进行修改原意是修改a,但是从上面的翻译中修改b只会对temp临时变量的值进行修改,而不会对a产生任何作用,因此C++要求此种情况下引用类型必须为const,这样就不会产生模糊不清的状况了。
函数中的const

[cpp] view plaincopyprint?
void function(const int Var); //传递过来的参数在函数内不可以改变(无意义,因为Var本身就是形参)  
  
void function(const char* Var); //参数指针所指内容为常量不可变  
  
void function(char* const Var); //参数指针本身为常量不可变(也无意义, 因为char* Var也是形参)  
[cpp] view plaincopyprint?
const int fun1() //无意义,参数返回本身就是赋值。  
  
const int * fun2() //即指针内容不可变。  
  
int* const fun3() //指针不可变,无意义   


类中的const

[cpp] view plaincopyprint?
void function(const Type &Var);   
const修饰引用时就变得很有必要了一是表明其在函数内为常量不可变,二也是比较常见的,我们都知道C++中的拷贝构造函数及赋值函数都是用了const引用,例如下例(Test表示类)
[cpp] view plaincopyprint?
const Test a;  
Test b;  
a = b;  

如果在赋值函数中没有const,上述的编译还能通过吗?(不能,原因const引用中已经介绍过)

终于到最后了,类中的const变量

在类中,有定义
[cpp] view plaincopyprint?
const int val;  
那么该val怎么初始化呢?直接初始化时不行了,C++不允许这样做。C++中有初始化链表,可以在调用构造函数时对其进行初始化,初始化链表的调用顺序与在链表的顺序无关,只与起申明顺序有关,另其调用在构造函数前。
用法
构造函数后
[cpp] view plaincopyprint?
Test():val(1)  
{  
...  
}  


当然按前面讲的,这里的const常量,已经退化为const只读变量了。

类中的const函数
[cpp] view plaincopyprint?
class Test  
{  
    private:  
        int val;  
    public :  
       void setValue()const   
        {  
            val = 1;  
        }   
};  
const在函数末尾表示该函数内部不能对类中变量进行修改,因此上述代码是不可能编译通过的,在C++中变量定义前对需要修改的变量前面加上mutable即可修改!

相关帖子

沙发
happygirlwz| | 2013-11-26 10:59 | 只看该作者
lz讲的很具体……!顶起……

使用特权

评论回复
板凳
wshww510| | 2013-12-9 18:59 | 只看该作者

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

主题

561

帖子

0

粉丝