• const 与指针(zz)


    1. 指向const对象的指针
    到目前位置,我们使用指针来修改其所指对象的值.但是如果指针指向const对象,则不允许用指针来改变其所指的const值.为了保证这个特性,C++语言强制要求指向const对象的指针也必须具有const特性:

    const double *cptr;   //cptr may point to a double that is const

    这里的cptr是一个指向double类型的const对象的指针,const限定了cptr指针所指向的对象类型,而并非cptr本身,也就是说,cptr本身并不是const.在定义时不需要对它进行初始化,如果需要的话,允许给cptr重新赋值,使其指向另一个const对象.但不能通过cptr修改其所指对象的值:

    *cptr=42;   //error:  *cptr might be const

    把一个const对象的地址赋给一个普通的、非const对象的指针也会导致编译时的错误:

    const double pi=3.14;
    double *ptr=π     //error:ptr is a plain pointer;Error message:error C2440: 'initializing' : cannot convert from 'const double *' to 'double *'
    const double *cptr=π   //ok:cptr is a pointer to const

    不能使用void*指针保存const对象的地址,而必须使用const void*类型的指针保存const对象的地址:

    const int universe=42;
    const void *cpv=&universe;  //ok:cpv is const;Error message:error C2440: 'initializing' : cannot convert from 'const int *' to 'void *'
    void *pv=&universe;    //error:universe is const

    允许把非const对象的地址赋给指向const对象的指针,例如:

    double dval=3.14;  //dval is a double; its value can be changed
    cptr=&dval;       //ok:but can't change dval through cptr

    尽管dval不是const对象,但任何企图通过指针cptr修改其值的行为都会导致编译时的错误.cptr一经定义,就不允许修改其所指对象的值.如果该指针恰好指向非const对象时,同样必须遵循这个规则.

    注解:不能使用指向const对象的指针修改基础对象,然而如果该指针指向的是一个非const对象,可用其他方法修改其所指的对象.

    事实是,可以修改const指针所指向的值,这一点常常容易引起误会.考虑:

    dval=3.14159;  //dval is not const
    *cptr=3.14159;  //error:cptr is a pointer to const
    double *ptr=&dval;  //ok:ptr points at non-const double
    *ptr=2.72;        //ok:ptr is plain pointer
    cout<<*cptr;      //ok:prints 2.72

    在此例题中,指向const的指针cptr实际上指向了一个非const对象.尽管它所指的对象并非const,但仍不能使用cptr修改该对象的值.本质上来说,由于没有办法分辨cptr所指的对象是否为const,系统会把它所指的所有对象都视为const.

    如果指向const的指针所指的对象并非const,则可直接给该对象赋值或间接地利用普通的非const指针修改其值;毕竟这个值不是const.重要的是要记住:不能保证指向const的指针所指对象的值一定不可修改.

    提示:如果把指向const的指针理解为"自以为指向const的指针",这可能会对理解有所帮助.因为它也可以指向非const的对象。

    在实际的程序中,指向const的指针常用作函数的形参.将形参定义为指向const的指针,以此确保传递给函数的实际对象在函数中不因为形参而被修改.

    2.const指针

    除指向const对象的指针外,C++语言还提供了const指针---------本身的值不能修改:

    int errNumb=0;
    int *const curErr=&errNumb;  //curErr is a constant pointer

    我们可以从右向左把上述定义语句读作"curErr是指向int型对象的const指针".于其他const量一样,const指针的值不能修改,这就意味着不能使curErr指向其他对象.任何企图给const指针赋值的行为(即使给curErr赋回同样的值)都会导致编译时的错误:

    curErr=curErr;   //error: curErr is const

    与任何const量一样,const指针也必须在定义时初始化.

    指针本身是const的事实并没有说明是否能使用该指针修改它所指向对象的值.指针所指对象的值能否修改完全取决于该对象的类型.例如,curErr指向一个普通的非常量int型对象errNumb,则可使用curErr修改该对象的值:

    if(*curErr){
     errorHandler();
     *curErr=0;  //ok: reset value of the object to which curErr is bound
    }

    3.指向const对象的const指针

    还可以如下定义指向const对象的const指针:

    const double pi=3.14159;
    //pi_ptr is const and points to a const object
    const double *const pi_ptr=&pi;

    本例中,既不能修改pi_ptr所指向对象的值,也不允许修改该指针的指向(即pi_ptr中存放的地址值).可从右向左阅读上述声明语句:"pi_ptr首先是一个const指针,指向double型的const对象".

    4.指针和typedef

    在typedef中使用指针往往会带来意外的结果.下面是一个几乎所有人刚开始都会答错的问题.假设给出以下语句:

    typedef string *pstring;
    const pstring cstr;

    请问cstr变量是什么类型?简单的回答是const pstring类型的指针.进一步问:const pstring指针所表示的真实类型是什么?很多人都认为真正的类型是:

    const string *cstr;   //wrong interpretation of const pstring cstr

    也就是说,const pstring是一种指针,指向string类型的const对象,但这是错误的.

    错误的原因在于将typedef当作文本扩展了.声明const pstring时,const修饰的是pstring的类型,这是一个指针.因此,该声明语句应该是把cstr定义为指向string类型对象的const指针,这个定义等价于:

    //cstr is a const pointer to string

    string *const cstr; //equivalent to const pstring cstr

    建议:理解复杂的const类型的声明

    阅读const声明语句产生的部分问题,源于const限定符既可以放在类型前也可以放在类型后:

    string const s1;  //s1 and s2 have same type
    const string s2;  //they're both strings that are const

    用typedef写const类型定义时,const限定符加在类型名前面容易引起对所定义的真正类型的误解:

    string s;
    typedef string *pstring;
    const pstring cstr1=&s;  //written this way the type is obscured
    pstring const cstr2=&s;  //all three decreations are the same type
    string *const cstr3=&s;  //they're all const pointers to string

    把const放在类型pstring之后,然后从右向左阅读该声明语句就会非常清楚地知道cstr2是const pstring类型,即指向string对象的指针.

    不幸的是,大多数人在阅读C++程序时都习惯看到const放在类型前面.于是为了遵循管理,只好建议编程时把const放在类型前面.但是,把声明语句重写为置const于类型之后更便于理解.


    习题4.19   解释下列五个定义的含义,指出其中哪些定义是非法的:

    a.  int i;
    b.  const int ic;
    c.  const int *pic;
    d.  int *const cpi;
    e.  const int *const cpic;

    a.合法:定义了int型对象i
    b.非法:定义const对象时必须初始化,但ic没有初始化
    c.合法:定义了指向int型const对象的指针pic
    d.非法:因为cpi被定义为指向int型对象的const指针,但该指针没有初始化
    e.非法:因为cpic被定义为指向int型const对象的const指针,但该指针没有初始化

    习题4.20  下列哪些初始化是合法的?为什么?

    a.  int i=-1;
    b.  const int ic=1;
    c.  const int *pic=&ic;
    d.  int *const cpi=&ic;
    e.  const int *const cpic=&ic;

    a.合法:定义了一个int型对象i,并用int型字面值-1对其进行初始化.
    b.合法:定义了一个int型const对象ic,并用int型对象对其进行初始化.
    c.合法:定义了一个指向int型const对象的指针pic,并用ic的地址对其进行初始化
    d.不合法:cpi是一个指向int型对象的const指针,不能用const int型对象ic的地址对其进行初始化.
    e.合法:定义了一个指向int型const对象的const指针cpic,并用ic的地址对其进行初始化.

    习题4.21  根据上述定义,下列哪些赋值运算是合法的?为什么?

    a. i=ic;
    b. pic=&ic;
    c. cpi=pic;
    d. pic=cpic;
    e. cpic=&ic;
    f. ic=*ipic;

    a、b、d合法
    其余均不合法.因为cpi、cpic和ic都是const变量(常量),常量不能被赋值

    总结:

  • 相关阅读:
    编程模式
    iOS----FMDB---看这个可以解决大部分你遇到的问题
    iOS UITableView的使用
    ios文件系统文件目录操作
    Core Data-备用
    数组去重复
    用法总结:NSArray,NSSet,NSDictionary-备用
    iOS 摇一摇的实现
    更改xcode上iphone模拟器颜色的方法--备用
    模式识别之基础---mqdf分类器==MQDF改进的二次分类器
  • 原文地址:https://www.cnblogs.com/whyandinside/p/1542692.html
Copyright © 2020-2023  润新知