const与指针,引用的结合

const 这个关键字会将所修饰的表达式置为常量,编译器会尽全力保证该表达式不可被修改,在const不和指针或者引用结合是,数据的类型是无关const的,可是若是一但和指针和引用相结合,那么考虑数据类型时候必需要考虑const了指针


class Test
{
public:
    Test(int data = 10):_ptr(new int(data)){}
    ~Test(){
        delete _ptr;
    }

    int GetInt(){
        return *_ptr;
    }
    int GetInt()const{
        return *_ptr;
    }

    int& GetIntRef(){
        return *_ptr;
    }
    int& GetIntRef()const{
        return *_ptr;
    }

    int* GetIntPtr(){
        return _ptr;
    }
    int* GetIntPtr()const{
        return _ptr;
    }  //  int *const _ptr

    int*& GetIntPtrRef(){
        return _ptr;
    }
    int*const& GetIntPtrRef()const{
        return _ptr;
    }
private:
    int *_ptr;
};

int main()
{
    Test t1;
    const Test t2;

    int a1 = t1.GetInt();
    int &b1 = t1.GetInt();
    const int &c1 = t1.GetInt();

    int a2 = t2.GetInt();
    int &b2 = t2.GetInt();
    const int &c2 = t2.GetInt();

    return 0;
}

举个例子,上面代码种有几处是有错误的,找出它~~~~

上面代码种b1是错误的,b2也是
先来看看b1,getInt返回的是一个整形值,它所返回的是一个当即数,那么用引用接收的时候就会出现没法给当即数取址的问题,此时寄存器带出的是一个当即数,而当即数不会有地址的,因此若是要引用,必须是一个常引用,不然编译不经过。
b2也是一样的,当即数不能取址code


那若是一开始返回的不是当即数而是一个引用呢?

int main()
{
    Test t1;
    const Test t2;

    int a1 = t1.GetIntRef();
    int &b1 = t1.GetIntRef();
    const int &c1 = t1.GetIntRef();

    int a2 = t2.GetIntRef();
    int &b2 = t2.GetIntRef();
    const int &c2 = t2.GetIntRef();

    return 0;
}

这样编译下来,并无什么问题,缘由是返回一个引用,此时会生成一个临时量,不存在当即数的问题了对象


那么咱们再来看看若是要是返回一个指针呢?

int main()
{
    Test t1;
    const Test t2;

    int *a1 = t1.GetIntPtr();
    int *&b1 = t1.GetIntPtr();
    const int *&c1 = t1.GetIntPtr();

    int *a2 = t2.GetIntPtr();
    int *&b2 = t2.GetIntPtr();
    const int *&c2 = t2.GetIntPtr();

    return 0;
}

此时又出现了刚才的问题,指针自己也是一个在32位系统下4字节的基础类型,因此返回值也会是一个当即数,不能取址,必须用常引用内存


简单总结一下:
对于赋值表达式的两边get

  1. 若是是值,只须要类型相同
  2. 若是是指针,要求必须能取地址
  3. 若是是引用,必须是能取地址,类型相同

再补充3个例子编译器

int*& GetIntPtrRef(){
        return _ptr;
    }
    int*const& GetIntPtrRef()const{
        return _ptr;
    }

int main()
{
    Test t1;
    const Test t2;

    int *a1 = t1.GetIntPtrRef();
    int *&b1 = t1.GetIntPtrRef();     
    const int *&c1 = t1.GetIntPtrRef();

    int *a2 = t2.GetIntPtrRef();
    int * &b2 = t2.GetIntPtrRef();
    const int *&c2 = t2.GetIntPtrRef();

    return 0;
}

此时编译下来有3个错误,本质上仍是类型不相同致使的,GetIntPtrRef()const的返回值是int const,可是b2是一个int *&,因此须要再&前面加上const保持类型相同
c2也是同样的道理,须要再引用前面加const编译

这里还有一个c1的错误,这个错误有些特殊,前面说过,const修饰的变量,编译器会尽力保证这个值不可被修改,此时const修饰的是&c1这个表达式,因此经过c1是不能修改的,可是此时却能够经过c1这个引用变量修改c1的内存,将引用换个指针就更加明显了,q,p这两个变量均可以修改同一片内存,此时咱们告诉编译器,q这是个常量,不许修改了,可是编译器发现经过*p竟然也能够修改这里的内存,必然是经过不了的。修改的话能够限定常引用,防止修改同一片内存class

const int *const &c1 = t1.GetIntPtrRef();

再看第二个

int ** GetIntPtrPtr()
{
    return &_ptr;
}
int *const* GetIntPtrPtr()const{
    return &_ptr;
}

int main()
{
    Test t1;
    const Test t2;

    int **a1 = t1.GetIntPtrPtr();
    int **b1 = t1.GetIntPtrPtr();
    const int **c1 = t1.GetIntPtrPtr();

    int **a2 = t2.GetIntPtrPtr();
    int **b2 = t2.GetIntPtrPtr();
    const int **c2 = t2.GetIntPtrPtr();

    return 0;
}

此时有4个错误,再常对象t2中_ptr是一个常量不可被修改的,因此 t2全部接收的类型都是int const ,故而a2,b2,c2都有错误
而c1中也就是那个特殊的错误,const修饰的变量编译器会尽力防止内存修改,因此应该是const int const 类型,故而c1也有错误基础


再来看看最后一个例子

int ** const& GetIntPtrPtrRef(){
    return &_ptr;
}
int *const * const& GetIntPtrPtrRef()const{
    return &_ptr;
}

int main()
{
    Test t1;
    const Test t2;

    int **a1 = t1.GetIntPtrPtrRef();
    int **b1 = t1.GetIntPtrPtrRef();
    const int **c1 = t1.GetIntPtrPtrRef();

    int **a2 = t2.GetIntPtrPtrRef();
    int **b2 = t2.GetIntPtrPtrRef();
    const int **c2 = t2.GetIntPtrPtrRef();

    return 0;
}

这个的错误和上个例子十分类似,在此很少赘述了。变量


总结:

  1. 等式的两边先进行类型的比较,须要注意const在右边没有*时候是不计算类型的,保证两边的类型首先相同。
  2. 其次注意const修饰的变量,指针或者引用是必需要求参数可以取地址的,若是是一个当即数的话,就必须注意要用常引用。
  3. 再就是那个特殊的错误,对于const与二级指针的结合,要求const修饰的对象的那块内存不能修改,因此两个*以前要么都有const,要么都没有。
相关文章
相关标签/搜索