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
再补充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; }
这个的错误和上个例子十分类似,在此很少赘述了。变量