C/C++中Static和Const的作用

一、const的作用 :


const关键字可以用于修饰变量,参数,返回值,甚至函数体。const可以提高程序的健壮性,减少程序出错。
 (一)const用于定义常量和修饰变量

   当定义某个变量时,用const修饰,则该变量就变为常量,其值定义后就不能再改变了,如:const int x=1;常量x的值不能再改变了。

TYPE const ValueName = value;  //TYPE表示数据类型int、long、float等
const TYPE ValueName = value; //TYPE表示数据类型int、long、float等

(1)const 修饰变量,表示该变量不能被修改。
  1、const char *p 表示指针p指向的内容不能改变
  2、char * const p,就是将P声明为常指针,它的地址不能改变。
  3、这种const指针是前两种的结合,使得指向的内容和地址都不能发生变化.

const double pi = 3.14159;//pi是常数
const double *const pi_ptr = π

(二)const修饰函数形式参数

  (1)传递过来的参数在函数内不可以改变(无意义,因为Var本身就是形参)

void function(const int Var);

  (2)参数指针所指的内容为常量不可变

void function(const char* Var);

  (3)参数指针本身为常量不可变(也无意义,因为char* Var也是形参)

void function(char* const Var);

  (4)参数为引用,为了增加效率同时防止修改。修饰引用参数时:

void function(const Class& Var); //引用参数在函数内不可以改变
void function(const TYPE& Var); //引用参数在函数内为常量不可变

   当输入参数为用户自定义类型和抽象数据类型时,将“值传递”改为“const&传递”可以提高效率,可以比较如下的代码:


void fun(A a);
void fun(A const& a);

   第一个函数效率较低,函数体内产生A类型的临时对象用于“值传递”参数a,而临时对象的构造、复制、析构过程都需要消耗资源和时间的,但使用第二种方式,按“引用传递”不需要产生临时对象,省了临时对象的构造、复制、析构的过程,因此效率较高。而之所以用const修饰a,是为了保证引用a不被修改。


 (二)const修饰函数返回值

 (1)函数按const指针 返回 ,表示该指针不能被改动,只能把该指针赋给const修饰的同类型指针变量。

const char *GetChar(void){};
char*ch=GetChar();//错误,按指针返回时,该函数返回值只能被赋值给const修饰的同类型指针
const char *ch=GetChar();//正确

  (2)函数按值返回,函数会把返回值赋给外部临时变量,用const无意义!不管是内部还是非内部数据类型。

int const get(){return this->n;}
int temp=i.get();//正确,按值传递时,接受返回值有无const均可

  (3)函数采用引用方式返回的场合不多,只出现在类的赋值函数中,目的是为了实现链式表达。


  (三)const修饰类的成员函数(函数定义体):


    通常,任何不需要修改数据成员的函数都应该声明为const类型,这样,如果const成员函数修改了数据成员或者调用了其他函数修改数据成员,编译器都将报错!

class stack
{
public:
int GetCount(void) const ;
private:
int m_num;
};
int stack::GetCount(void) const
{
m_num++;
}

编译器输出错误信息:error C2166: l-value specifies const object。

例题: 给定声明 const char * const * pp; 下列操作或说明正确的是?


  A.pp++
  B.(*pp)++
  C.(**pp) = \\c\\;
  D.以上都不对
  正确答案: A  
【详细解释 】:const 限定一个对象为只读属性。 


    分析的原则:

char const *ptr:若const限定符在*之前,则const限定的是*ptr。也就是说,ptr可以改变其所指向的对象,但不能通过该指针修改其所指向对象的值。
若const限定符在*之后,则const限定的是ptr而不限定*ptr。也就是说,ptr不可以改变其所指向的对象,但能通过该指针修改其所指向对象的值。
若在*之前有const限定符且在*之后也有const限定符,则ptr与*ptr都被限定。也就是说,ptr既不可以改变其所指向的对象,也不能通过该指针修改其所指向对象的值。先从一级指针说起吧:


(1)const char p  //限定变量p为只读。这样如p=2这样的赋值操作就是错误的。 

(2)const char *p  //p为一个指向char类型的指针,const只限定p指向的对象为只读。这样,p=&a或  p++等操作都是合法的,但如*p=4这样的操作就错了,因为企图改写这个已经被限定为只读属性的对象。 (const 限定*p,即限定p指向的内容)

(3)char *const p  限定此指针为只读,这样p=&a或  p++等操作都是不合法的。而*p=3这样的操作合法,因为并没有限定其最终对象为只读。 (const直接与p结合,因此这里只限定了指针本身p,但内容可以修改 )

(4)const char *const p 两者皆限定为只读,不能改写。 (结合方向:const char *(const p))

   有了以上的对比,再来看二级指针问题: 

(1)const char **p  p为一个指向指针的指针,const限定其最终对象为只读,显然这最终对象也是为char类型的变量。故像**p=3这样的赋值是错误的,而像*p=? p++这样的操作合法。 

(2)const char * const *p 限定最终对象和 p指向的指针为只读。这样 *p=?的操作也是错的。 

(3)const char * const * const p 全部限定为只读,都不可以改写。