const 用法总结

const 用法总结(C++)

--------------------------------------------------------------------------------


根据个人的学习和理解,下面我将从以下几个分类来进行讨论,如有错误之处,还请各位大虾多多指教!(部分内容直接转载,以供学习和参考)

--------------------------------------------------------------------------------

一、关于一般常量
声明或定义的格式如下:
const <类型说明符> <变量名> = <常量或常量表达式>; [1]
<类型说明符> const <变量名> = <常量或常量表达式>; [2]
[1]和[2]的定义是完全等价的。
 
例如:
整形int(或其他内置类型:float,double,char)
const int bufSize = 512;
或者
int const bufSize = 512;
 
因为常量在定义后就不能被修改,所以定义时必须初始化。
bufSize = 128;  // error:attempt to write to const object
const string cntStr = "hello!"; // ok:initialized
const i, j = 0; // error: i is uninitialized const
 
非const变量默认为extern。
const 对象默认为文件的局部变量。 要使 const变量能够在其他的文件中访问,必须显式地指定它为extern。
 
例如:
const int bufSize = 512;        // 作用域只限于定义此变量的文件
extern const int bufSize = 512; // extern用于扩大作用域,作用域为整个源程序(只有extern 位于函数外部时,才可以含有初始化式)
 
二、关于数组及结构体
声明或定义的格式如下:
const <类型说明符> <数组名>[<大小>]…… [1]
<类型说明符> const <数组名>[<大小>]…… [2]
[1]和[2]的定义是完全等价的。
 
例如:
整形int(或其他内置类型:float,double,char)
const int cntIntArr[] = {1,2,3,4,5};
或者
int const cntIntArr[] = {1,2,3,4,5};
 
struct SI
{
    int i1;
    int i2;
};
const SI s[] = {{1,2},{3,4}};
// 上面的两个const都是变量集合,编译器会为其分配内存,所以不能在编译期间使用其中的值(例如:int temp[cntIntArr [2]], 这样的话编译器会报告不能找到常量表达式)
 
三、关于引用
声明或定义的格式如下:
const <类型说明符> &<变量名> = …… [1]
<类型说明符> const &<变量名> = …… [2]
[1]和[2]的定义是完全等价的。
 
例如:
const int i = 128;
const int &r = i;(或者 int const &r = i;)
const 引用就是指向const 对象的引用。
普通引用不能绑定到const 对象,但const 引用可以绑定到非const 对象。
const int ii = 456;
int &rii = ii; // error
int jj = 123;
const int &rjj = jj; // ok
 
非const 引用只能绑定到与该引用同类型的对象。
const 引用则可以绑定到不同但相关的类型的对象或绑定到右值。
例如:
1.const int &r = 100;     // 绑定到字面值常量
2.int i = 50;
  const int &r2 = r + i;  // 引用r绑定到右值
3.double dVal = 3.1415;
  const int &ri = dVal;   // 整型引用绑定到double 类型
编译器会把以上代码转换成如下形式的编码:
int temp = dVal;      // create temporary int from double
const int &ri = temp; // bind ri to that temporary
 
四、关于指针
1.指向const 对象的指针 (指针所指向的内容为常量)
声明或定义的格式如下(定义时可以不初始化):
const <类型说明符> *<变量名> …… [1]
<类型说明符> const *<变量名> …… [2]
[1]和[2]的定义是完全等价的。
 
例如:
const int i = 100;
const int *cptr = &i;
或者
int const *cptr = &i; [cptr 是指向int 类型的const 对象的指针]
 
允许把非const 对象的地址赋给指向const 对象的指针 ,例如:
double dVal = 3.14;          // dVal is a double; its value can be change
const double *cdptr = &dVal; // ok;but can't change dVal through cdptr
不能使用指向const 对象的指针修改基础对象。然而如果该指针指向的是一个没const 对象(如cdptr),可用其他方法修改其所指向的对象。
 
如何将一个const 对象合法地赋给一个普通指针?
例如:
const double dVal = 3.14;
double *ptr = &dVal; // error
double *ptr = const_cast<double *>( &dVal);
// ok: const_cast是C++中标准的强制转换,C语言使用:d ouble * ptr = (double*)&dVal ;
 
2.const 指针 (指针本身为常量)
声明或定义的格式如下(定义时必须初始化):
<类型说明符> *const <变量名> = …… 
 
例如:
int errNumb = 0;
int iVal = 10;
int *const curErr = &errNumb; [curErr 是指向int 型对象的const 指针]
 
指针的指向不能被修改。
curErr = &iVal; // error: curErr is const
指针所指向的基础对象可以修改。
*curErr = 1; // ok:reset value of the object(errNumb) which curErr is bind
 
3.指向const 对象的const 指针 (指针本身和指向的内容均为常量)
声明或定义的格式如下(定义时必须初始化):
const <类型说明符> *const <变量名> = ……
 
例如:
const double pi = 3.14159;
const double dVal = 3.14;
const double *const pi_ptr = &pi; [pi_ptr 是指向double 类型的const 对象的const 指针]
 
指针的指向不能被修改。
pi_ptr = &dVal; // error: pi_ptr is const
指针所指向的基础对象也不能被修改。
*pi_ptr = dVal; // error: pi is const
 
五、关于一般函数
1.修饰函数的参数
class A;
void func1(const int i);  // i不能被修改
void func3 (const A &rA);        //  rA所引用的对象不能被修改 
void func2 (const char  *pstr);  // pstr所指向的内容不能被修改
 
2.修饰函数的返回值


返回值 :const int func1(); // 此处返回int 类型的 const 值,意思指返回的原函数里的变量的初值不能被修改,但是函数按值返回的这个变量被制成副本,能不能被修改就没有了意义,它可以被赋给任何的 const 或非 const 类型变量,完全不需要加上这个 const 关键字。这样的写法是非常没有必要的。但是要真的碰到了这样的定义,我们要以如下的方式使用: 如const int ff(); //返回的是常量,所以必须这么调用 const int a=ff();

 

 
返回引用 :const int &func2(); // 注意千万不要返回局部对象的引用,否则会报运行时错误:因为一旦函数结束,局部对象被释放,函数返回值指向了一个对程序来说不再有效的内存空间。
函数返回值采用“引用传递”的场合并不多,这种方式一般只出现在类的赋值函数中,目的是为了实现链式表达。
例如:
class A
{
A & operate = (const A &other); // 赋值函数
};
A a, b, c; // a, b, c 为A 的对象

a = b = c; // 正常的链式赋值
(a = b) = c; // 不正常的链式赋值,但合法
如果将赋值函数的返回值加const 修饰,那么该返回值的内容不允许被改动。 上例中,语句 a = b = c 仍然正确,但是语句 (a = b) = c 则是非法的。

 
返回指针 :const int *func3(); // 注意千万不要返回指向局部对象的指针,因为一旦函数结束,局部对象被释放,返回的指针变成了指向一个不再存在的对象的悬垂指针。另外, 以“指针传递”方式的函数返回值加const修饰,那么函数返回值(即指针)的内容不能被修改,该返回值只能被赋给加const修饰的同类型指针。例如函数 const char * GetString(void);
如下语句将出现编译错误:char *str = GetString();
正确的用法是:const char *str = GetString();
这个对左值的保护有帮助:
char *Function1()
{ return “Some text”;}
这个程序会在下边的语句中崩溃掉。

Function1()[1]=’a’;
然后,要是如下写这个函数,加上const限定词

const char *Function1()
{ return "Some text";}
编译器就会报错了。

 

 
六、关于类
class A
{
public:
    void func();
    void func() const;
    const A operator+(const A &) const;
private:
    int num1;
    mutable int num2;
    const size_t size;
};
1.修饰成员变量
const size_t size; // 对于const 的成员变量,[1]必须在构造函数里面进行初始化;[2]只能通过初始化成员列表来初始化;[3]试图在构造函数体内对const 成员变量 进行初始化 会引起编译错误。
例如:
A::A(size_t sz):size(sz) // ok:使用初始化成员列表来初始化
{
}
A::A(size_t sz)
{
    size = sz; // error:试图在构造函数体内对const 成员变量 进行初始化
}

 
2.修饰类成员函数
const 成员函数的声明看起来怪怪的:const 关键字只能放在函数声明的尾部,大概是因为其它地方都已经被占用了。


void func() const; // const成员函数中不允许对数据成员进行修改, 并且不允许调用了其它非const 成员函数, 如果出现以上情况,编译器将报错。如果某成员函数不需要对数据成员进行修改,最好将其声明为const 成员函数,这将大大提高程序的健壮性。
 
const 为函数重载提供了一个参考
class A
{
public:
    void func();       // [1]:一个函数
    void func() const; // [2]:上一个函数[1]的重载
    ……
};
A a(10);
a.func(); // 调用函数[1]
const A b(100);
b.func(); // 调用函数[2] 
 
如何在const成员函数中对成员变量进行修改?
下面提供几种方式(只提倡使用第一种 ,其他方式不建议使用)
(1)标准方式:mutable, 加上mutable修饰符的数据成员,对于任何情况下通过任何手段都可修改,自然此时的const成员函数是可以修改它的 。

class A
{
public:
    A::A(int i):m_data(i){}
    void SetValue(int i){ m_data = i; }
private:
    mutable int m_data;  // 这里处理
};
(2)强制转换:static_cast
class A
{
public:
    A::A(int i):m_data(i){}
    void SetValue(int i)
    { static_cast<int>(m_data) = i; } // 这里处理
private:
    int m_data;
};
(3)强制转换:const_cast 
class A
{
public:
    A::A(int i):m_data(i){}
    void SetValue(int i)
    { const_cast<A*>(this)->m_data = i; } // 这里处理
private:
    int m_data;
};
(4)使用指针:int *
class A
{
public:
    A::A(int i):m_data(i){}
    void SetValue(int i)
    { *m_data = i; } // 这里处理
private:
    int *m_data;
};
(5)未定义的处理方式
class A
{
public:
    A::A(int i):m_data(i){}
    void SetValue(int i)
    { int *p = (int*)&m_data; *p = i } // 这里处理
private:
    int m_data;
};
注意:这里虽然说可以修改,但结果是未定义的,避免使用!
 
3.修饰类对象
const A a; // 类对象a 只能调用const 成员函数,否则编译器报错。也就是说, const对象只能访问const成员函数,但是非const对象可以访问任意的成员函数,包括const成员函数。 const对象的成员是不可修改的,然而const对象通过指针维护的对象却是可以修改的.
 
4.修饰类成员函数的返回值
const A operator+(const A &) const; // 前一个const 用来修饰重载函数operator+的返回值,可防止返回值作为左值进行赋值操作。
例如:
A a;
A b;
A c;
a + b = c; // errro: 如果在没有const 修饰返回值的情况下,编译器不会报错。
 
七、使用const的一些建议
  
1.要大胆的使用const,这将给你带来无尽的益处,但前提是你必须搞清楚原委; 
2.要避免最一般的赋值操作错误,如将const变量赋值,具体可见思考题;
3.在参数中使用const应该使用引用或指针,而不是一般的对象实例,原因同上; 
4.const在成员函数中的三种用法(参数、返回值、函数)要很好的使用;
5.不要轻易的将函数的返回值类型定为const;
6.除了重载操作符外一般不要将返回值类型定为对某个对象的const引用;
 
八、cons有什么主要的作用?
1. 可以定义const常量,具有不可变性。
例如:
const int Max=100;
int Array[Max];

2.便于进行类型检查,使编译器对处理内容有更多了解,消除了一些隐患。
例如:
void f(const int i) { .........}
编译器就会知道i是一个常量,不允许修改;

3.可以避免意义模糊的数字出现,同样可以很方便地进行参数的调整和修改。
同宏定义一样,可以做到不变则已,一变都变!如(1)中,如果想修改Max的内容,只需要:const int Max=you want;即可!

4.可以保护被修饰的东西,防止意外的修改,增强程序的健壮性。
还是上面的例子,如果在函数体内修改了i,编译器就会报错;
例如:
void f(const int i) { i=10;//error! }

5.为函数重载提供了一个参考。
class A
{
    ......
    void f(int i)       {......} file:// 一 个函数
    void f(int i) const {......} file:// 上 一个函数的重载
    ......
 };

6.可以节省空间,避免不必要的内存分配。
例如:
#define PI 3.14159         file:// 常 量宏
const doulbe  Pi=3.14159;  file://此 时并未将Pi放入ROM中
 ......
double i=Pi;               file://此 时为Pi分配内存,以后不再分配!
double I=PI;               file://编 译期间进行宏替换,分配内存
double j=Pi;               file://没 有内存分配
double J=PI;               file://再 进行宏替换,又一次分配内存!

const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝。

7.提高了效率。
编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。


本文出自 “将弛直奔 ” 博客,请务必保留此出处http://cnmtjp.blog.51cto.com/204390/35976

 

 

 

阅读更多
个人分类: C、C++笔记
上一篇陈志武《金融的逻辑》
下一篇我常去的编程技术网站
想对作者说点什么? 我来说一句

const 用法总结.

2008年08月27日 22KB 下载

const用法详解

2012年05月23日 41KB 下载

C++ const应用总结

2009年12月09日 144KB 下载

Dan_Saks总结const所有用法

2011年03月22日 54KB 下载

c++中的const总结

2008年07月23日 3KB 下载

Dan Saks总结const所有用法

2008年10月26日 48KB 下载

C++中const用法总结

2009年09月26日 3KB 下载

关于const在C++中的用法

2011年09月15日 4KB 下载

没有更多推荐了,返回首页

关闭
关闭
关闭