C++中const用法解释(最全)

 

 

 

 
# include <iostream>
using namespace std;

class A
{
public:
int a;
int b;
};

int main(void)
{
//const int a; 在Vc6.0中会报错
//const double x; 在Vc6.0会报错
const int *p; // 在Vc6.0为什么不会报错
const class A *pA; // 在Vc6.0为什么不会报错
const class A aa; // 在Vc6.0为什么不会报错

return 0;
}
/*
奇怪,为什么在Vc6.0++中:
定义基本类型的常变量必须在定义的同时初始化
但为什么定义基本类型的常指针变量在定义的同时就可以不初始化
定义常类对象和指向类的常指针变量时也可以在定义时不初始化
*/
 
 

 

 

 
C/C++ # include <iostream>   using namespace std;
class A { public:
int a; int b;
};

int main()

{

const int*p;

// const int *p; const修饰的是*p,所以不能通过*p来修改其指向的值,但是p本身可以被修改,所以不用直接赋值

const class A*pA;

// 原因同上

const class A aa;

 // const对象只能调const函数,构造函数会赋值初始化对象,你还要怎么初始化呢?

return0;

}

 

 

 

 
const的资料

C++中const总结

一:对于基本声明
  1.const int r=100; 
  //标准const变量声明加初始化,因为默认内部连接所以必须被初始化,其作用域
  为此文件,编译器经过类型检查后直接用100在编译时替换.

  2.extend const int r=100; 
  //将const改为外部连接,作用于扩大至全局,编译时会分配内存,并且可以不进行
  初始化,仅仅作为声明,编译器认为在程序其他地方进行了定义.

  3.const int r[]={1,2,3,4};
  struct S {int a,b;};
  const S s[]={(1,2),(3.4)};
  //以上两种都是常量集合,编译器会为其分配内存,所以不能在编译期间使用其中
  的值,例如:int temp[r[2]];这样的编译器会报告不能找到常量表达式

二:对于指针
  1.const int *r=&x; 
  //声明r为一个指向常量的x的指针,r指向的对象不能被修改,但他可以指向任何
  地址的常量.
 
  2.int const *r=&x;//与用法1完全等价,没有任何区别。

  3.int * const r=&x; 
  //声明r为一个常量指针,他指向x,r这个指针的指向不能被修改,但他指向的地址
  的内容可以修改.

  4.const int * const r=&x; 
  //综合1,3用法,r是一个指向常量的常量型指针.

三:对于类型检查
  可以把一个非const对象赋给一个
指向const的指针,因为有时候我们不想从这个
  指针来修改其对象的值,但是不可以把一个const对象赋值给一个非const指针,
  因为这样可能会通过这个指针改变指向对象的值,但也存在使这种操作通过的合
  法化写法,使用类型强制转换可以通过指针改变const对象:
  const int r=100;
  int *ptr=const_cast<int*>(&r);//C++标准,C语言使用:int* ptr =(int*)&r;

四:对于字符数组
  如char * name = "china"; 
  这样的语句,在编译时是能够通过的,但是"china"是常量字符数组,任何想修改
  他的操作也能通过编译但会引起运行时错误,如果我们想修改字符数组的话就要
  使用char name[]="china";这种形式.

五:对于函数
  1.void Fuction1(const int r);
  //此处为参数传递const值,意义是变量初值不能被函数改变

  2.const int Fuction1(int); 
  //此处返回const值,意思指返回的原函数里的变量的初值不能被修改,但是函数
  按值返回的这个变量被制成副本,能不能被修改就没有了意义,它可以被赋给任何
  的const或非const类型变量,完全不需要加上这个const关键字.但这只对于内部
  类型而言(因为内部类型返回的肯定是一个值,而不会返回一个变量,不会作为左
  值使用),对于用户自定义类型,返回值是常量是非常重要的,见下面条款3

  3.Class CX; //内部有构造函数,声明如CX(int r =0)
  CX Fuction1 () { return CX(); }
  const CX Fuction2 () { return CX(); }
  如有上面的自定义类CX,和函数Fuction1()和Fuction2(),我们进行如下操作时:
  Fuction1()=CX(1); //没有问题,可以作为左值调用
  Fuction2()=CX(1); //编译错误,const返回值禁止作为左值调用.因为左值
  把返回值作为变量会修改其返回值,const声明禁止这种修改.

  4.函数中指针的const传递和返回
  int F1 (const char * pstr); 
  //作为传递的时候使用const修饰可以保证不会通过这个指针来修改传递参数的
  初值,这里在函数内部任何修改*pstr的企图都会引起编译错误.
  const char* F2(); 
  //意义是函数返回的指针指向的对象是一个const对象,它必须赋给一个同样是指
  向const
对象的指针.
  const char* const F3(); 
  //比上面多了一个const,这个const的意义只是在他被用作左值时有效,它表明这
  个指针除了指向const对象外,它本身也不能被修改,所以就不能当作左值来处理.

  5.函数中引用的const传递
  void F1 (const X& px); 
  //这样的一个const引用传递和最普通的函数按值传递的效果是一模一样的,他禁
  止对引用
的对象的一切修改,唯一不同的是按值传递会先建立一个类对象的副本,
  然后传递过去,而它直接传递地址,所以这种传递比按值传递更有效.

  另外只有引用的const传递可以传递一个临时对象,因为临时对象都是const属性,
  且是不可见的,他短时间存在一个局部域中,所以不能使用指针,只有引用的const
  传递能够捕捉到这个家伙.
6.对于类
  1.首先,对于const的成员变量,只能在构造函数里使
用初始化成员列表来初始化,
  试图在构造函数体内进行初始化const成员变量会引起编译错误.初始化成员列表
  形如:X::X(int ir):r(ir){} //假设r是类X的const成员变量

  2.const成员函数.提到这个概念首先要谈到const对象,正象内置类型能够定义
  const对象一样(const int r=10;),用户自定义类型也可以定义const对象
  (const X px(10);),编译器要保证这个对象在其生命周期内不能够被改变.
  如果你定义了这样的一个const对象,那么对于这个对象的一切非const成员函数的
   调用,编译器为了保证对象的const特性,都会禁止并在编译期间报错.所以如果你想
  让你的成员函数能够在const对象上进行操作的话,就要把这个函数声明为const
  成员函数.
  假如f()是类中的成员函数的话,它的声明形如:
  int f()const; 
  //const放在函数的最后,编译器会对这个函数进行检查,在这个加有const
  函数中的任何试图改变成员变量和调用非const成员函数的操作都被视为非法
  注意:类的构造和析构函数都不能是const函数.

  3.建立了一个const成员函数,但仍然想用这个函数改变对象内部的数据.这样的
  一个要求也会经常遇到,尤其是在一个苛刻的面试考官那里.首先我们要弄清楚考
  官的要求,因为有两种方法可以实现,如果要求不改变原来类的任何东西,只让你从
  当前这个const成员函数入手,那么你只有使用前面提到的类型强制转换方法.实例
  如下:
  //假如有一个叫做X的类,它有一个int成员变量r,我们需要通过一个const成员函
  数f()来对这个r进行++r操作,代码如下:
  void X::f()const
  {const_cast<X*>(this)->++r; } //通过this指针进行类型强制转换实现
  另外一种方法就是使用关键字:mutable.
  如果你的成员变量在定义时是这个样子的:mutable int r;
  那么它就告诉编译器这个成员变量可以通过const成员函数改变.编译器就不会再
  理会对他的检查了

 

 

 

 
关键看的是const修饰的是什么,是不允许改变哪个值
const 修饰基本类型,就是常量数据,自然需要初始化
const 修饰指针,这样之后就阻止修改指针所指向的值,而不是指针,所以对于指针来说它是一个变量,对于指针所指向的数据来说是个常量
 

 

 

 
下面我也贴一个我在C学习中的对cosnt的心得

/*
2007-4-21
type * cosnt p; 与 type cosnt *p; 的区别
*/

# include <stdio.h>

int main(void)
{
int i = 3;
int *const p = &i;
int j;

//p = &j; 这样会报错!
*p = 5;
printf("*p = %d\n",*p);

*(p+4) = 10; /* 这实在是很危险的操作,可惜Vc++6.0检测不到这种错误,连警告都没有! 唉。。。。。 */
printf("*(p+4) = %d\n",*(p+4));

return 0;
}

/*
先看下面这个在Vc++6.0 中会报错的程序
# include <stdio.h>

int main(void)
{
int *const p;
int i = 3;

p = &i;

printf("*p = %d\n",*p);

return 0;
}
Vc++6.0显示: "1-4.cpp(10) : error C2734: 'p' : const object must be initialized if not extern"


  再看一个在Vc++6.0中仍会报错的程序:
# include <stdio.h>

int main(void)
{
int i = 3;
int *const p;

p = &i;

printf("*p = %d\n",*p);

return 0;
}
Vc++6.0显示: "1-4.cpp(11) : error C2734: 'p' : const object must be initialized if not extern"


  原程序是正确的!
  
  总结:
  type * const p; 不可以修改p得值,但可以修改p所指向得内存单元,就连(p+i)所指向得内存单元在VC6.0++中也可以修改!

  OK 我们最后总结一下:
   
第一: type const *p; 等价于 const type *p; 这两个都是只允许修改p的值,但不能修改*p 的值,也不能修改*(p+i)的值!  
第二: type * cosnt p; 是const的另外一种法! 它不允许你修改p的值,但允许你修改p所指向得内存单元,也允许你修改
(p+i)所指向的内存单元!
 
郝斌
 

 

c++ const变量
1.常变量
1.1.定义:在定义变量时,如果加上关键字const,则变量的值在程序运行期间不能改变。
1.2.在定义常变量时必须同时对它初始化(即指定其值),此后这的值不能再改变。如:
    const int a=3;  //正确
    如下面是错误的:
    const int a;
    a=3;            //常变量不能被赋值

2.对象中的常数据成员
2.1.只能通过构造函数的参数初始化表对常数据成员进行初始化。
2.2.不能采用在构造函数中对常数据成员赋初值的方法。

3.指向对象的常指针:
3.1.定义指向对象的常指针的一般形式为:
    类名 * const 指针变量名;
    也可以在定义指针变量时使之初始化,如:
    Time * const ptr1=&t1;  //指定ptr1指向t1
3.2.注意点:
    指向对象的常指针变量的值不能改变,即始终指向同一个对象,但可以改变其所指向对象(如t1)的值。
3.3.指向对象的常指针的使用场合:
    如果想将一个指针变量固定地与一个对象相联系(即该指针变量始终指向一个对象),可以将它指定为 const型指针变量。这样可以防止误操作,增加安全性。
3.4.往往常指针作为函数的形参,目的是不允许在函数执行过程中改变指针变量的值,使其始终指向原来的对象。

4.指向常变量的指针变量
4.1.定义指向常变量的指针变量的一般形式为:
    const 类型名 *指针变量名; 例如:const char *ptr;
4.2.说明:
    (1)如果一个变量已被声明为常变量,只能用指向常变量的指针变量指向它,
     而不能用一般的(指向非const型变量的)指针变量去指向它。如
     const char c[]="boy";    //定义const型的char数组
     const char *p1;         //定义p1为指向const型的char变量的指针变量
     p1=c;                   //合法,p1指向常变量(char数组的首元素)
     char *p2=c;             //不合法,p2不是指向常变量的指针变量
    (2)指向常变量的指针变量除了可以指向常变量外,还可以指向未被声明为const的变量。
     此时不能通过此变量改变该变量的值。如:
     char c1='a';   //定义字符变量c1,它并未声明为const
     const char *p; //定义了一个指向常变量的指针变量p
     p=&c1;         //使p指向字符变量c1
     *p='b';        //非法,不能通过p改变变量c1的值
     c1='b';        //合法,没有通过p访问c1,c1不是常变量
    (3)如果函数的形参是指向非const型变量的指针,实参只能用指向非const变量的指针,
     而不能用指向const变量的指针,这样,在执行函数的过程中可以改变形参指针变量所指向
     的变量(也就是实参指针所指向的变量)的值。
     如果函数的形参是指向const型变量的指针,在执行函数过程中显然不能改变指针变量所
     指向的变量的值,因此允许实参指向const变量的指针,或指向非const变量的指针。如:
     const char str[]="boy"; //str是const型数组名
     void fun(char *ptr);    //函数fun的形参是指向非const型变量的指针
     fun(str);           //调用fun函数,实参是const变量的地址,非法
    (4)总结:指向常变量的指针变量可以指向const和非const型的变量,而指向非const型变量
     的指针变量只能指向非const的变量。

5.指向常对象的指针变量
5.1.指向常变量的指针变量,指向常对象的指针变量的概念和使用是与此类似的,只要将"变量"
    换成"对象"即可。
5.2.如果一个对象已被声明为常对象,只能用指向常对象的指针变量指向它,
     而不能用一般的(指向非const型对象的)指针变量去指向它。
5.3.如果定义了一个指向常对象的指针变量,并使它指向一个非const的对象,则其指向的对象
    是不能通过指针来改变的。如:
    Time t1(10,12,15);   //定义Time类对象t1,它是非const型对象
    const Time *p=&t1;  //定义p是指向常对象的指针变量,并指向t1
    t1.hour=18;         //合法,t1不是常变量
    (*p).hour=18;       //非法,不能通过指针变量改变t1的值
    注:如果希望在任何情况下t1的值都不能改变,则应把它定义为const型对象,如:
    const Time t1(10,12,15);
5.4.注意指向常对象的指针变量与指向对象的常指针变量在形式上和作用上的区别.
    Time *const p;   //指向对象的常指针变量
    const Time *p;   //指向常对象的指针变量
5.5 指向常对象的指针常用于函数的形能,目的是在保护形参指针所指向的对象,使
    它在函数执行过程中不被修改。
5.6.当希望在调用函数时对象的值不被修改,就应当把形能定义为指向常对象的指针变量,
    同时用对象的地址作实参(对象可以是const或非const型)。
    如果要求该对象不仅在调用函数过程中不被改变,而且要求它在程序执行过程中都不改变,则应把这 定义为const型。
5.7.如果定义了一个指向常对象的指针变量,是不能通过它改变所指向的对象的值的,但是指针变量本身的值是可以改变的。如:
    const Time *p=&t1; //定义指向常对象的指针变量p,并指向对象t1
    p=&t2;             //p改为指向t2,合法

6.对象的常引用
6.1.如果不希望在函数中修改实参t1的值,可以把引用变量t声明为const(常引用),函数原型为:
    void fun(const Time &t);
    则在函数中不能改变t的值,也就是不能改变其对应的实参t1的值。

7.在C++面向对象程序设计中,经常用常指针和常引用作函数参数,这样既能保证数据安全,使数据不能被随意修改,在调用函数时又不必实参的拷贝。用常指针和常引用作函数参数,可以提高程序运行效率。
8.用常对象作函数参数较少,因其内存开销开。

9.以上参考谭教授<C++程序设计>教程,在些感谢


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值