现在的位置: 首页 > 综合 > 正文

浅析带const的指针或引用复杂声明

2013年08月15日 ⁄ 综合 ⁄ 共 3920字 ⁄ 字号 评论关闭

C++中的const与non-const、指针和引用本来就搞得人头晕了,再把复杂的声明结合在一起,比如看下面这个
 const double * const &  crcdval = &cdval;
你看的明白吗?呵呵,如果不是很明白,那就读一读我的这篇心得吧。

●复杂的ptr和const声明

#include <iostream>
#include <vector>
using namespace std;

struct X
{
   X(int i) : m_i(i) { }
   int m_i;
};
void main()
{

   // 我把每个变量的类型都写出来了
   // correct
   const X cx(10);
   const X * pcx = &cx;
   //typeof(pcx) = const X (*)
   const X * const cpcx = &cx;
   //typeof(cpcx) = const X (*const)

   cout << sizeof(const X *const(*const(*const))) << endl;

   const X * const * ppcx = &pcx;
   //typeof(ppcx) = const X (*const(*))
   const X * const * const cppcx = &cpcx;
   //typeof(cppcx) = const X (*const(*const))

   const X * const * const * const cpcpcpx = &cppcx;
   //typeof(cppcx) = const X (*const(*const(*const)))

   cout << &(vector<int>()) << endl;
   cout << sizeof(int(& (*)(int[20],int&,double**))[100]) << endl;
}

 今天才发现原来以前C++老师讲const时讲错了,const int * p 和 int const * p是等价的,p为pci: Pointer to a const int(const int *);而int * const p中p为cpi:const pointer to int(int *const),我也一直都记错了。

 另外,比如
 const X * const * const cppcx = &cpcx;
    //typeof(cppcx) = const X (*const(*const))

    里面的第2个const可能会让很多人迷惑。我的理解是:它既修饰前面的指向const X的指针本身,看成是"const T *const"的后面那个const;又修饰了后面的那个指针*,说明它指向的对象是const的,看成是"T const *"的形式,其中的T展开就是const X*.

 

    利用编译原理中的词法生成规则来描述它,我们可以清楚地看到这个声明语句是怎么得来的。
    首先定义生成规则:

    产生式:{
  指针的声明语句→T id [= exp];
  T→(const T)|(T const) * [const]
         }
   
    上面的那个复杂的声明语句的推导过程:

  指针的声明语句 => T id = exp; 
   => T const * const id = exp;
   => const X * const * const id = exp;
   => const X * const * const cppcx = &cpcx;
    这里的两个理解其实是等价的,因为这是一个多重指针,第2个指针指向的就是第一个指针里面的地址值。
所以第一个指针本身是const和指向这第一个指针的第二个指针所指向的对象为const当然是一样的了。
    以前我老是觉得,C++中为什么不规定只使用单一形式的const,而要这样搞的两个形式等价,现在看来其实应该是const T *用的人很多,而T const * 又是语法所必须的,所以就无从取舍。当然可以只保留T const *的形式:)。&的写法与此类似,只是只有const T&和T const&,而由于referrence本身的要求,就是一个const的了,所以没有T & const的写法.       

●为什么这个const不能少

今天偶尔看到《c++ Primer》中讲referrence的那一章中有个例子,

const double cdval = 3.14;
 const double * pcd = &cdval;
 const double * const &  crcdval = &cdval;

 double dval = 6.28;
 double * const & rd = &dval;

 书上说到其中的第3行,很可能大部分人都不能把它直接写对,因为里面的两个const一个都不能少!
需要前面的那个const是显然的,如果去掉cl会提示
error: a value of type "const double *" cannot be used to initialize an entity of type "double *const &"
即从const type到non-const type的转化是不允许的。

而如果去掉第二个const会怎么样呢?(可以只通过最后2行的例子来说明这个问题)
error: initial value of reference to non-const must be an lvalue
 我觉得,第2个const可以理解做同时修饰(*const)和(const&),这就点和复杂的ptr和const声明一样,稍后会解释。这里因为&dval是non-lvalue表达式,而没有const修饰&,则它必须用一个lvalue表达式来初始化,故错误;而根据修饰转换的原则,non-const type 到const type的转化是允许的.就是"const double *"可以转化为"const double *const &" 所以只有两个const都加上才能通过编译。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         

抱歉!评论已关闭.