前几天我们QQ群提出了这么一个问题:
请问:
int **const a;
int *const * a;
int const** a;
他们的区别?
我下线后就写了一些测试程序来作为我对这个问题的理解:
程序1:关于**const============================
#include <iostream>
#include <conio>
using namespace std;
//------------------------------
int main(int argc, char* argv[])
{
int a=123;
int b=456;
int c=789;
int *pa=&a;
int *pb=&b;
int *pc=&c;
int **const ppa=&pa; //ppa 是常量 ,ppa必须先初始化,否则会有错误编译错误发生
cout<<**ppa<<endl;
getch();
/*
ppa=&pb; //无法修改ppa的值,进一步说明ppa是常量
cout<<**ppa;
getch();
*/
*ppa=&c; //*ppa是可以修改的
cout<<**ppa<<endl;
getch();
**ppa=777; //**ppa是变量修改了**ppa就是修改了c的值
cout<<"**ppa="<<**ppa<<endl;
cout<<"c ="<<c <<endl;
getch();
}
程序2:关于*const*============================
#include <iostream>
#include <conio>
using namespace std;
int main(int argc, char* argv[])
{
int a=123;
int b=456;
int c=789;
int *pa=&a;
int *pb=&b;
int *pc=&c;
int **ppt=&pc;
int *const* ppa=&pa; //ppa初始化与否都无所谓,说明ppa是变量
cout<<"(long)( ppa)"<<(long)( ppa)<<endl;
cout<<"(long)( *ppa)"<<(long)( *ppa)<<endl;
cout<<"(long)(**ppa)"<<(long)(**ppa)<<endl; //如果ppa不初始化,这个语句会产
//生异常(至少在我的机子上是这样)
cout<<"(long)( &pa)"<<(long)( &pa)<<endl;
cout<<"(long)( pa)"<<(long)( pa)<<endl;
getch();
ppa=&pc;
/*
//注意:下面说的使用是指修改其值,而不仅是读取其值
*ppa=pc;//无论ppa是否初始化这一句总是产生编译错误=>编译器提示:无法修改一个const对象
//由此可见*ppa是一个常量,我们无法修改*ppa的值,而无论ppa是否初始化都一样。
//如果ppa不初始化,那么ppa和*ppa都指向一个随机地址,由于*ppa的值无法改变,所以
//这时使用ppa和*ppa是安全的(这一点很有意思,或许我们可以利用这一点作点什么)但
//是,如果使用**ppa就是错误的;
*/
**ppa=777; //这一句能够顺利执行,说明**ppa是可以被修改的
cout<<"**ppa="<<**ppa<<endl;
cout<<"a ="<<a <<endl;//修改了**ppa就是修改了a的值
getch();
return 0;
}
程序3:关于*const*============================
#include <iostream>
#include <conio>
using namespace std;
#pragma argsused
int main(int argc, char* argv[])
{
int a=123;
int b=456;
int c=789;
int *pa=&a;
int *pb=&b;
int *pc=&c;
int **ppc=&pc;
int const d=888;
int const*pd=&d;
int const**ppd=&pd;
int const e=888;
int const*pe=&e;
int const**ppe=&pe;
int const** ppa=ppd;/*
这个更有意思:ppa不能在定义时用&pa或ppc初始化,一旦写
了初始化代码就会有下面的编译错误发生
Cannot convert 'int * *' to 'const int * *'
但是可以用ppd初始化
*/
/*
ppa=&pa;//即使在定义后初始化也是上面一样的错误
*/
ppa=ppe;//这一句是可以的表明ppa并不具有常量的性质ppa是可以改变的
//但是只能指向与自己同类型的两量
/*
*ppa=pc; //这一句会有"程序访问非法地址"的错
//误所以这样用是错的。但是,不是编
//译期错误,这就说明*ppa是可以更改的量(虽然是不合法的)
//而不是属于 const 的。//这里的分析好象有问题大家还是讨论讨论
*/
*ppa=pe; //但是,这一句倒是可行的
// ppc=ppe; //这两句仍然有前面一样的编译错误:说明ppc是常量性质的无法更改其值
/*
**ppa=777;//这一句会有无法修改const对象的错误
//这说明**ppa是常量性质的
*/
getch();
return 0;
}
总结:============================
由const修饰的量是常量性质的!该量的值不可更改.
**const
*const*
const**
例如:
const* p ==> *p 不能更改,但是 p 自己的值是可以改变的
const** p==> **p 不能更改,但是 *p 和 p 的值是可以改变的
*const* p==> *p 不能更改,但是 p 和 **p的值是可以改变的
**const p==> p 不能更改,但是 *p 和 **p的值是可以改变的
这个const好象在我们“向改写的对象赋值过程中,进行寻址时”
加了一把锁或一堵墙:他修饰谁,谁就不能被赋值寻址时被
找到(编译期错误,当然读取都是允许的)。
通过这我们可以了解到:
const int& AA::func(const int&x )const;
│ │ └修饰整个成员函数:不该变类的内部数据
│ └修饰参数:该函数不改变外部参数x的值
├修饰返回值:调用该函数的代码不能改变返回的引用值(否则
└ 我们才可以这样用fun(a)=12// 事实上我们每个人都这样用过:cout<<...<<...)
通过这些也可以推导出:Type const*const*const a 的意义! 大家不妨试一试!