您的位置:首页 > 编程语言 > C语言/C++

谈谈C++中的const

2013-10-11 17:53 169 查看
const修饰变量
还是先从C谈起吧,在学习C语言的时候就知道const修饰的是常量,其值是不可改变的,真的是这样吗?

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++里面呢?稍微修改一下上面的代码。

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退化。

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指向的内容不可修改,右边指针本身不可被修改。

const int *a;       	
int const *a;         //*a不可改变
int *const a;        //a不可变,需在定义的时候初始化
const int *const a;  //a及*a均不可变,需在定义的时候初始化

const引用
这里只是简单介绍一下,下面会有更详细的说明

int main()
{
    const int &a = 1;   //这里会为1分配内存空间,&指向这片内存空间
    int *b = (int *)&a; //
    *b = 2;
    cout<<a<<endl;
  return 0;
}


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


编译后发现第一段是错误的,这个是很好理解的,非const的引用怎么能用const变量初始化呢,那么下面的呢?

float a = 1.0;
    int &b = a;

结果是编译不通过,但是如果改为const int &b = a;编译就可以通过了,比较奇怪?考虑其在编译器中的实现,以上代码翻译为

float a = 1.0;
    int temp = a;
    int &b = temp;


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

void function(const int Var); //传递过来的参数在函数内不可以改变(无意义,因为Var本身就是形参)

void function(const char* Var); //参数指针所指内容为常量不可变

void function(char* const Var); //参数指针本身为常量不可变(也无意义, 因为char* Var也是形参)


const int fun1() //无意义,参数返回本身就是赋值。

const int * fun2() //即指针内容不可变。

int* const fun3() //指针不可变,无意义



类中的const
void function(const Type &Var);


const修饰引用时就变得很有必要了一是表明其在函数内为常量不可变,二也是比较常见的,我们都知道C++中的拷贝构造函数及赋值函数都是用了const引用,例如下例(Test表示类)

const Test a;
Test b;
a = b;


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

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

在类中,有定义

const int val;

那么该val怎么初始化呢?直接初始化时不行了,C++不允许这样做。C++中有初始化链表,可以在调用构造函数时对其进行初始化,初始化链表的调用顺序与在链表的顺序无关,只与起申明顺序有关,另其调用在构造函数前。
用法
构造函数后

Test():val(1)
{
...
}


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

类中的const函数

class Test
{
    private:
        int val;
    public :
       void setValue()const  
        {
            val = 1;
        }  
};

const在函数末尾表示该函数内部不能对类中变量进行修改,因此上述代码是不可能编译通过的,在C++中变量定义前对需要修改的变量前面加上mutable即可修改!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: