c++中const关键字浅析

const关键字可以修饰很多东西使其变成常量,用以保护被修饰的东西,下面我列出了一些我遇到的使用情况。

指针常量和常量指针

    const修饰指针的时候,可以按*号分成左右。如果const在*左面,那么就是指针常量(pointer to const),意味着*p这个值不能变,也就是说不能通过这个指针修改它指向的那块地址的值。如果const在*右面,那么就是常量指针(const pointer),这个指针可以通过*x的方式修改地址的值,那时不能通过x=&b的形式修改x中的地址。如下图,指针常量是黄色地址内的值不变,常量指针是蓝色地址内的值不变。

2}ZED0FIS{X`J8_B2QUTM98.jpg

#include <stdio.h>
int main() {
    int a = 10, b = 20;
    const int *p = &a;
    const int* t = &a;
    int* const x = &a;
    int const *y = &a;
    *p = 11;//编译错误 *p不能修改
    *t = 11;//编译错误 *t不能修改
    *x = 11;
    *y = 11;//编译错误 *y不能修改
    p = &b;
    t = &b;
    x = &b;//编译错误 x不能修改
    y = &b;
    printf("%d\n", *t);
    return 0;
}

函数中使用const

1. const修饰函数参数

参数指针所指内容为常量不可变

void function(const char* Var);

参数为引用,为了增加效率同时防止修改。修饰引用参数时:

void function(const Class& Var); //引用参数在函数内不可以改变

void function(const TYPE& Var); //引用参数在函数内为常量不可变

2. const 修饰函数返回值

const int * fun1() //调用时 const int *pValue = fun2(); string的c_str()就是定义为const char* 为了防止用户改动其中的内容
int* const fun2()   //调用时 int * const pValue = fun2();

    一般情况下,函数的返回值为某个对象时,如果将其声明为const时,多用于操作符的重载。通常,不建议用const修饰函数的返回值类型为某个对象或对某个对象引用的情况。原因如下:如果返回值为某个对象为const(const A test = A 实例)或某个对象的引用为const(const A& test = A实例) ,则返回值具有const属性,则返回实例只能访问类A中的公有(保护)数据成员和const成员函数,并且不允许对其进行赋值操作,这在一般情况下很少用到。

类中的const

1. const修饰成员变量

const修饰类的成员变量,表示成员常量,不能被修改,同时它只能在初始化列表中赋值。

class A { 
    //…
    const int nValue;         //成员常量不能被修改
    //…
    A(int x): nValue(x) { } ; //只能在初始化列表中赋值
};


2. const修饰成员函数

const修饰类的成员函数,则该成员函数不能修改类中任何非const成员函数。一般写在函数的最后来修饰。这里的const可以作为类成员函数重载的依据,因为const是修饰的隐形参数this。

class A { 
    void function() const;
};

对于const类对象/指针/引用,只能调用类的const成员函数,因此,const修饰成员函数的最重要作用就是限制对于const对象的使用。

a. const成员函数不能修改它所在对象的任何一个数据成员,但是可以访问(可读不可写)。

b. const成员函数不能够访问对象的非const成员函数。

3. 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(); //正确

const_cast将常量转化成变量

如果想将常量地址赋值给非常量指针,就会编译错误,提示不能将const type转化成type。使用const_type可以解决这个问题。

#include <stdio.h>

int main() {
    const int a = 10;
    int *p = const_cast<int *>(&a);
    *p = 20;
    int& x = const_cast<int&>(a);
    int y = const_cast<int&>(a);
    x = 30;
    y = 40;
    printf("*p = %d\n", *p);
    printf("a = %d\n", a);
    printf("x = %d\n", x);
    printf("y = %d\n", y);
    printf("p = %p\n", p);
    printf("&a = %p\n", &a);
    printf("&x = %p\n", &x);
    printf("&y = %p\n", &y);
    return 0;
}

这段代码的输出很有意思,输出如下:

*p = 30
a = 10
x = 30
y = 40
p = 0xbf817000
&a = 0xbf817000
&x = 0xbf817000
&y = 0xbf817004

    两个量的地址一样但是输出的值不一样,const依旧是const不管如何的变化其中的值也不会变。转为指针和引用时地址不变,转为变量时,赋值的时候存在一次类型转换,有一次变量的复制,所以地址是新的。

    上面的代码是对内置数据类型做的实验,对class或者struct对象的话,指针和引用是可以改变对象的原始值的。推测是因为第12行代码printf("a = %d\n", a);在编译时a的值直接被替换为了10。

留言: