void*为“无类型指针”,可以指向任何类型的数据,但是访问数据时必须指明。
看下面的小例子:
int a = 5; void *p = &a; cout<<*p; //编译错误,'void*' is not a pointer-to-object type cout<<*(int*)p; //ok cout<<*(double*)p; //可以通过编译和运行,但是结果肯定是错误的
其实,void* 指针能做的事情很有限:1.指针比较。2.作为函数传入参数,或返回参数。3.赋给另一个void* 指针。
不能通过void* 指针来访问它所指的对象(因为我们不知道对象的类型,而对象类型决定了可以进行哪些操作。),如果想访问它所指的类型,需要显式指出。
int i = 42; int *p = &i; //指针p指向i int *&r = p; //r是指针p的引用,r是一个指向int类型的指针的引用 *r = 50; //here, i==50, *p == 50
int i = 42; const int &r1 = i; //ok r1 = 100; //error, cause it's const i = 100; cout << r1; //here, r1==100
const引用可以用普通对象来初始化,但是不能通过cont引用来修改该对象。看下面的小例子:
double dval = 3.14; const int &r1 = dval; dval = 3.15; cout<<r1; //ri == 3
这里,可以用const引用绑定不是该类型的对象(int r1 = dval;就不可以)。其实这里引用绑定的是一个临时对象。相当于:
const int temp = dval; //创建了一个临时对象,为3 const int &r1 = temp; //将引用与临时对象绑定,所以结果输出为3
指针不可能知道它所指向的对象是const对象还是普通对象,所以它对它所指向的所有对象都当成是const对象。指向const对象的指针可以被认为是“它们认为它们自己指向const对象的指针”。
不能通过该指针修改对象的值,不过可以改变该指针指向的对象。
const double pi = 3.14; double *ptr = π //error,不能用普通指针存储const对象地址 const double *cptr = π //ok *cptr = 42; //error,不能通过const指针赋值 double dval = 3.14; cptr = &dval; //ok:但是不能通过cptr来改变dval的值
//可以改变该指针的指向对象 const int v1 = 3; const int v2 = 4; const int *p = &v1; cout<<*p<<endl; //output 3 p = &v2; //改变指向的对象 cout<<*p<<endl; //output 4
任何给const指针重新指向新对象的做法都是错误的。不过,可以通过const指针修改对象的值。
int errNumb = 0; int *const curErr = &errNumb; //curErr will always point to errNumb const double pi = 3.14159; const double *const pip = π //pip is a const pointer to a const object
最简单的理解方式是从右往左读,curErr is a constant pointer to an object of type int.
//可以改变该指针指向对象的值 int v3 = 5; int v4 = 10; int *const p2 = &v3; *p2 = 6; //ok,改变该对象的值 p2 = &v4; //error,因为是const指针,不能重新指向新对象 cout<<*p2<<endl; //output 6
总结:指向const对象的指针 和 const指针 是不同的。前者认为自己指向的对象是const,所以不能通过该指针修改对象的值;后者认为自己是const指针,不能重新指向新对象。前者可以指向新对象,后者可以更改对象的值。一般来说,前者用的更广泛,常用于函数的传入参数,来保证在函数体中不改变对象的值。