1  const变量

const double PI = 3.14159;

定义之后不能被修改,所以定义时必须初始化。

const int i, j = 0;  // error: i is uninitialized const

const变量默认为文件的局部变量,此变量只存在于那个文件中,不能被其他文件访问。通过指定const变更为extern,就可以在整个程序中访问const变量。

// file_1.c
extern const int bufSize = fcn(); // file_2.c
extern const int bufSize;
for (int index = 0; index != bufSize; index++)
//...

2  const和指针

const和指针有两种交互类型:指向const对象的指针和const指针。

2.1 指向const对象的指针 —— “自以为指向const对象的指针”

const double *cptr; // cptr may point to a double that is const

在上面的语句中,const限定的是cptr指针所指向的对象,而不是cptr本身,也就是说,cptr本身并不是const, 所以不需要对cptr进行初始化。如果需要的话,允许给cptr重新赋值,但是不能通过cptr修改其所指对象的值:

*cptr = 42; //error: *cptr might be const

C++为了保证不允许用指针来改变const对象的值,强制要求指向const对象的指针必须具有const特性,所以把const对象的地址赋给一个普通的非const对象的指针也会导致编译时错误:
const double pi = 3.14;
double * ptr = π // error: ptr is a plain pointer
const double * cptr = π // ok: cptr is a pointer to const

这条规则对于void *指针也是必须的, 即不能使用void *指针保存const对象的地址,而必须使用const void *型的指针保存const对象的地址。

const double pi = 3.14;
const void *cpv = π // ok
void *pv = π //error
允许把非const对象的地址赋给指向const对象的指针,例如:
double pi = 3.14;
const double * cptr = π // ok, but can't change pi through cptr

2.2 const指针

const指针,指针本身的值不能修改。和其他const常量一样,const指针的值是不能修改的,这就意味着不能使const指针指向其他对象。
double pi = 3.14;
double pi2 = 6.28;
double * const conptr = π
conptr = &pi2; // error: conptr is const

2.3 指向const对象的const指针

可以如下定义指向const对象的const指针:
const double pi = 3.14;
// pi_ptr is const and points to a const object
const double * const pi_ptr = π

可以从右向左阅读上述声明语句:”pi_ptr首先是一个const指针,指向double类型的const对象“。


3  const引用——“自以为指向const对象的引用”

在说明const引用之前,先复习一下引用的一些特性:

  • 引用必须和同类型的对象相关联;
  • 初始化是指明引用指向哪个对象的唯一方法;
  • 当引用初始化后,它就保持绑定到初始化时指向的对象,不能将引用绑定到另一个对象。
int a = 1024;
int &refa1 = a; // ok
int &refa2; // error
int &refa3 = 2048; // error: mismatch type

现在来看看特殊的引用:const引用。

const引用是指向const对象的引用。之所以不是“引用是const”,是因为引用本身就被默认为const,当一个引用被定义时,必须被初始化,绑定到一个对象上,并且不可以改变。

const int ival = 1024;
const int &refVal = ival; //ok
int &ref2 = ival; //error: nonconst reference to a const object.

所谓的“自以为指向const对象的引用”的意思是,const引用也可以指向非const对象,效果就是不可以通过这个引用来修改所指对象的值,即,这个引用是只读的。

int z = 0;
const int &refZ = z;
refZ = 1; //error.

const引用和普通引用的一个不同的地方是:const引用可以初始化为不同类型的对象或者右值(如字面值常量)。

int i = 42;
const int &refI = 42; // ok
const int &refI2 = i + 42; //ok

对于引用绑定到不同类型的对象:

double dval = 3.14;
const int &ri = dval;

编译器会把这些代码转换成如下形式的代码:

double dval = 3.14;
int temp = dval; // create temporary int from the double
const int &ri = temp; //bind ri to that temporary

4  函数中使用const

4.1 指向const对象的指针的形参

比较常见的用法是保证传入的参数不被修改,所以一般将函数参数声明为指向const对象的指针:
void function(const char* Var); // 参数指针所指内容为常量,不可改变

4.2 const引用类型的形参

void function(const string & s1); // s1是一用,所以不复制形参,又因为形参是const引用,所以该函数不能修改是s1引用对象的内容。

优点:避免复制形参,提高效率,同时防止修改实参。

同时更大的优点是,const引用类型的形参更灵活:

如上述定义的函数传递的形参可以是一个一个字符串常量,如:

function("hello world");

因为const引用形参可以与不同类型的对象相关联。

但是如果将函数声明为如下的形式:

void function(string & 2);

由于非const引用形参只能与完全同类型的非const对象关联,所以再传递字符串常量就会发生编译错误。

5  类中使用const

5.1 const成员函数

class A
void function(const char* Var);
{
void function_1();
void function() const;
}

用这种方式使用const的函数称为常量成员函数。

在解释这个const所起的作用之前,回忆一下,每个成员函数都有的一个额外的隐含的形参this。

考虑下面的调用语句:

a.function_1();

编译器会这样重写这个函数调用:

A::function_1(&a);

即隐含的this初始化为调用函数的对象的地址。

那么跟在函数声明的形参表后面的const所起的作用就是:改变this形参的类型。

在调用a.function()时,隐含的this形参将是一个指向a对象的const A*类型的指针。

const成员函数的特性:

  • const成员函数不可以修改它所在对象的任何一个数据成员
  • const成员函数能够访问对象的const成员,而其他成员函数不可以
  • const对象,指向const对象的指针或引用只能用于调用其const成员函数,如果尝试用它们来调用非const成员函数,是错误的。

5.2 const成员变量

初始化const成员变量必须在执行构造函数的函数体之前完成,所以,唯一的机会就是在构造函数初始化列表中初始化const成员变量。

Class A
{
...
private:
const int nValue; public:
......
A(int x): nValue(x) { ... }; }

下面的构造函数是错误的:

class ConstRef
{
public:
ConstRef(int ii);
private:
int i;
const int ci;
int &ri;
}; ConstRef::ConstRef(int ii)
{
i = ii;
ci = ii; // error: cannot assign to a const
ri = i;
}

正确的构造函数应该这样:

ConstRef::ConstRef(int ii): i(ii), ci(i), ri(ii) {}

没错,引用类型数据成员和const成员变量一样,初始化的唯一机会是在构造函数初始化列表中。

5.3 特殊的整型const static 成员

先回忆一下类的static成员的基本性质:

通常,static数据成员不像普通数据成员,static成员不是用过类构造函数进行初始化,由于static成员只能被初始化一次,所以应该在定义时初始化,且在类的定义体外部定义。

#include<iostream>
using namespace std; class Tester
{
public:
static int a;
}; int Tester::a = 10; int main()
{
cout << Tester::a << endl;
return 0;
}

不需要实例化这个类,即可访问static成员。

这个规则的一个例外就是:只要初始化式是一个常量表达式,整型const static 数据成员就可以在类的定义体中进行初始化,需要注意的是,该数据成员仍必须在类的定义体之外进行定义,而不必再指定初始值。

#include<iostream>
using namespace std; class Tester
{
public:
const static int b = 0;
}; const int Tester::b; int main()
{
cout << Tester::b << endl;
return 0;
}

这个程序在电脑上编译通过,但是遭到管家报警自动删除,警报为后门程序。。

参考资料:

《C++Primer(4th)》

《C++高级编程(2th)》

const关键字浅析的更多相关文章

  1. PHP的final关键字、static关键字、const关键字

    在PHP5中新增加了final关键字,它可以加载类或类中方法前.但不能使用final标识成员属性,虽然final有常量的意思,但在php中定义常量是使用define()函数来完成的. final关键字 ...

  2. C++中const关键字的使用总结

    C++中使用const关键字来修饰常量,下面从两个方面总结:变量和成员函数. 变量:const可以修饰普通变量.指针(数组)和结构体. 1.const修饰普通变量是最简单的情形.这样的用法多为在程序中 ...

  3. final关键字+const关键字

    final关键字 1.如果我们希望某个类不被其它的类来继承(可能因为安全考虑),可以使用final. 例题 <? final class A{} class B extends A{};//会报 ...

  4. C++学习11 类和new、delete操作符 类与const关键字

    如果你是Java.C#.PHP程序员,那么会对 new 非常熟悉,在这些编程语言中,只能通过 new 来创建对象. 在C++中,你可以像定义变量一样来创建对象,如: Student stu; //对象 ...

  5. C++中的const关键字

    http://blog.csdn.net/eric_jo/article/details/4138548 C++中的const关键字的用法非常灵活,而使用const将大大改善程序的健壮性,本人根据各方 ...

  6. 陈正冲老师讲c语言之const关键字

    1.const 关键字也许该被替换为 readolny const是constant的缩写,是恒定不变的意思,也翻译为常量.常数等.很不幸,正是因为这一点,很多人都认为被const修饰的值是常量.这是 ...

  7. C语言之头文件,static与const关键字

    [前言] 最近几个月在做一个C语言代码重构的项目,过程中也让我对之前在书本上学习到的东西有些补充和巩固,在本博中总结记录下,梳理下零碎的知识点和经验也加深印象,书写是为了更好地思考.平时也都是用印象笔 ...

  8. static和const关键字的作用

    static关键字至少有下列n个作用: (1)函数体内static变量的作用范围为该函数体,不同于auto变量,该变量的内存只被分配一次,因此其值在下次调用时仍维持上次的值: (2)在模块内的stat ...

  9. const关键字详解

    const在函数前与函数后的区别 一   const基础         如果const关键字不涉及到指针,我们很好理解,下面是涉及到指针的情况:         int   b   =   500; ...

随机推荐

  1. C语言 · 数字三角形

    算法训练 数字三角形   时间限制:1.0s   内存限制:256.0MB      问题描述 (图3.1-1)示出了一个数字三角形. 请编一个程序计算从顶至底的某处的一条路 径,使该路径所经过的数字 ...

  2. Android—— TextView文字链接4中方法

    转自:http://ghostfromheaven.iteye.com/blog/752181 Android 的实现TextView中文字链接的方式有很多种. 总结起来大概有4种: 1.当文字中出现 ...

  3. 4种用于构建嵌入式linux系统的工具_转

    转自:4种用于构建嵌入式linux系统的工具 Linux 被部署到比 Linus Torvalds 在他的宿舍里开发时所预期的更广泛的设备.令人震惊的支持了各种芯片,使得Linux 可以应用于大大小小 ...

  4. nodejs 模块以及加载机制,主要讨论找不到模块的问题

    最主要的一个思想,加载模块无非就是找到模块在哪,只要清楚了模块的位置以及模块加载的逻辑那么找不到模块的问题就迎刃而解了.本文只是综合了自己所学的知识点进行总结,难免出现理解错误的地方,请见谅. nod ...

  5. js学习笔记15----子节点和兄弟节点的操作

    1.元素.firstChild : 只读属性,第一个子节点 标准下:会包含文本类型的子节点. 非标准下:只包含元素类型子节点. 元素.firstElementChild : 只读属性,第一个元素子节点 ...

  6. LVS学习笔记及总结(思维导图版)

    转自: http://www.07net01.com/2015/10/944377.html 下图是我在跟随马哥的脚步学习LVS过程中的学习笔记,以此为蓝本总结的,若有不足之处请谅解!

  7. 免费 web api 接口大全

    下面的接口来自互联网,部分功能需要付费 查询手机 http://www.yodao.com/s-martresult-xml/search.s?type=mobile&q= 手机号码 查询 I ...

  8. php 删除目录

    <?php /* 自定义的删除函数,可以删除文件和递归删除文件夹 */ function my_del($path)//自定义my_del函数,函数有一个参数($path).当调用my_del( ...

  9. 使用ffmpeg步骤

    av_register_all();//初始化ffmpeg库,如果系统里面的ffmpeg没配置好这里会出错  if (isNetwork) {      //需要播放网络视频      avforma ...

  10. ffmpeg 编解码详细过程

    ffmpeg编解码详细过程     bobbypollo 转:ffmpeg编解码详细过程 原文地址:ffmpeg编解码详细过程(转)作者:心在飞翔原文出处: http://www.360doc.com ...