C/C++ const关键字

1. const 在C和C++中的区别

(1)在C中,const变量是一个“不能被改变的普通变量”,既然是变量,就要占用存储空间,所以编译器不知道编译时的值,所以在C中可以这么写:

const int size; //被看做一个声明,它会在别的地方分配存储空间

但不能这么写:

const int size=100;

char buf[size]; //因为size不是常量

在C++中,const被看成编译期的常量,编译器并不为const分配空间,但必须在初始化时赋值,并且可以作为数组的维数。因此,可以这么写:

const int size=100;

char buf[size]; //因为size是常量

(2)C++中const默认是内部连接,而C中使用外部连接.C++中要想使用外部变量,必须用extern声明(注意:声明应用的变量不能是const)

   内连接:编译器只对正被编译的文件创建存储空间,别的文件可以使用相同的表示符或全局变量.C/C++中内连接使用static关键字指定.

   外连接:所有被编译过的文件创建一片单独存储空间.一旦空间被创建,连接器必须解决对这片存储空间的引用.全局变量和函数使用外部连接.通过extern关键字声明,可以从其他文件访问相应的变量和函数.C++中,是否为const分配空间要看具体情况. 如果加上关键字extern或者取const变量地址,则编译器就要为const分配存储空间.

如:

a.cpp中:

const int a=10;

b.cpp中:

const int a=20;

cout<<a<<endl;

则编译正确,输出结果为20

但如果改为:

a.cpp中:

int a=10;

b.cpp中:

int a=20;

cout<<a<<endl;

则显示 fatal error LNK1169: 找到一个或多个多重定义的符号

再比如:

a.cpp中:

const int a=10;

b.cpp中:

extern const int a;

cout<<a<<endl;

则会编译出错:无法解析的外部符号 "int const a"

但改为

a.cpp中:

extern const int a=10;

b.cpp中:

extern const int a;

cout<<a<<endl;

则正确,C++中const变量默认只能在本文件中可见,但是如果加上extern则可以抑制const的这种特性


C++中定义常量的时候不再采用define,因为define只做简单的宏替换,并不提供类型检查.


2.const指针和指向const的指针

在C语言中const指针表示该指针是一个常量,一旦进行初始化完成之后就无法改变它指向的位置。指向const的指针说明使用这个指针无法改变其指向的地址处的值,特别强调的一点是使用这个指针不能够改变。言外之意就是说,可以通过其他的方式改变。

比如:char ch='c';

const char *ptr=&ch;

*ptr='a';//这样做是不允许的

ch='a';//这样做完全可以,并且*ptr的值也是'a'

const int* a = & [1]          //非常量数据的常量指针    指针常量
int const *a = & [2]          //非常量数据的常量指针     a is a pointer to the constant char variable
int* const a = & [3]          //常量数据的非常量指针指针常量 常量指针 a is a constant pointer to the (non-constant) char variable
const int* const a = & [4]    //常量数据的常量指针

如果const位于星号*的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;
如果const位于星号的右侧,const就是修饰指针本身,即指针本身是常量。
因此,[1]和[2]的情况相同,都是指针所指向的内容为常量,这种情况下不允许对内容进行更改操作,如不能*a = 3 ;
[3]为指针本身是常量,而指针所指向的内容不是常量,这种情况下不能对指针本身进行更改操作,如a++是错误的;
[4]为指针本身和指向的内容均为常量。 

3.const修饰引用

  int const &a=x;
   const int &a=x;
   int &const a=x;//这种方式定义是C、C++编译器未定义,虽然不会报错,但是该句效果和int &a一样。   
                   //这两种定义方式是等价的,此时的引用a不能被更新。如:a++ 这是错误的。

4.const应用到函数中  

(1)修饰参数的const

   如 void fun0(const A* a ); void fun1(const A& a);
   调用函数的时候,用相应的变量初始化const常量,则在函数体中,按照const所修饰的部分进行常量化,如形参为const A* a,
   则不能对传递进来的指针的内容进行改变,保护了原指针所指向的内容;
   如形参为const A& a,则不能对传递进来的引用对象进行改变,保护了原对象的属性。
   [注意]:参数const通常用于参数为指针或引用的情况; 
(2)修饰返回值的const

   如const A fun2( ); const A* fun3( );
   这样声明了返回值后,const按照"修饰原则"进行修饰,起到相应的保护作用。

   const Rational operator*(const Rational& lhs, const Rational& rhs)
   {
            return Rational(lhs.numerator() * rhs.numerator(),
            lhs.denominator() * rhs.denominator());
   }
  返回值用const修饰可以防止允许这样的操作发生:
   Rational a,b;
   Radional c;
   (a*b) = c;
   一般用const修饰返回值为对象本身(非引用和指针)的情况多用于二目操作符重载函数并产生新对象的时候。
    类中的成员函数:A fun4()  const; 其意义上是不能修改所在类的的任何变量。 

5. 类中定义常量

(1)使用枚举类型 
class test
{
     enum { SIZE1 = 10, SIZE2 = 20}; // 枚举常量
     int array1[SIZE1];  
     int array2[SIZE2];
};

(2)使用const 
  不能在类声明中初始化const数据成员。以下用法是错误的,因为类的对象未被创建时,编译器不知道SIZE的值是什么。 
  class test
  {
        const int SIZE = 100;     // 错误,企图在类声明中初始化const数据成员
        int array[SIZE];          // 错误,未知的SIZE
  };

  只有静态常量整型数据成员才可以在类中初始化

  class test
  {
        static const int SIZE = 100;     // 正确
        int array[SIZE];                     // 正确
  };

  但是静态变量必须在类外定义

  class test
  {
     public:
static int SIZE = 100;     // 错误,只有静态常量整型数据成员才可以在类中初始化
  };


  正确的使用const实现方法为:const数据成员的初始化只能在类构造函数的初始化表中进行。 
class A
{…
A(int size);      // 构造函数
const int SIZE ; 
};
A::A(int size) : SIZE(size)    // 构造函数的初始化表
{
 …
}
     //error 赋值的方式是不行的
A::A(int size)
{
SIZE=size;
}
void main()
{
A  a(100); // 对象 a 的SIZE值为100
A  b(200); // 对象 b 的SIZE值为200
}
  注意:对const成员变量的初始化,不能在变量声明的地方,必须在类的构造函数的初始化列表中完成,即使是在构造函数内部赋值也是不行的。

   当const放在类成员函数的后面:

   class test

   {

       public:

           void f( int a) const {};

   }

  表示这是一个常成员函数。常成员函数可以理解为是一个“只读”函数,它既不能更改数据成员的值,也不能调用那些能引起数据成员值变化的成员函数,只能调用const成员函数。

#include<iostream>  
using   namespace   std;  
class A{  
    int   data;  
  public:  
      A(int   da=100):data(da){}  
      void   display1(){cout<<data<<endl;}  
      void   display2()   const   {cout<<data<<endl;}  
      void   display3()   const  
      {      
            data+=100;  
            cout<<data<<endl;  
      }  
};  

int   main()  
{  
	A   a1;  
	const   A   a2;  
	a1.display1();  
	a1.display2();      
	a1.dispaly3();       //error   ,const声明的成员函数不能改变数据成员的值  
	a2.display1();       //error   ,const对象不能调用非const函数  
	a2.display2();       //right  
	a2.display3();       //error   ,const对象不能调用非const函数,且不能改变数据成员值  	
	return   0;  
}


const修饰成员函数总结

(1) const对象只能访问const成员函数,而非const对象可以访问任意的成员函数,包括const成员函数.
(2)const对象的成员是不可修改的,然而const对象通过指针维护的对象却是可以修改的.

(3)const成员函数不可以修改对象的数据,不管对象是否具有const性质.它在编译时,以是否修改成员数据为依据,进行检查.

(4)然而加上mutable修饰符的数据成员,对于任何情况下通过任何手段都可修改,自然此时的const成员函数是可以修改它的




  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值