最近在做那个故障树分析和推理诊断项目,其中的推理诊断部分是用c++来写的,毕竟是对火箭的故障分析,甲方突然要求推理结果的精度要很高,让使用贝叶斯网络。找到几种方案,觉得intel的PNL文档比较齐全,应该靠谱,暂时还在研究PNL中。扯远了。。。

推理这部分出于性能各方面的考虑用到了不少const,但是不能稀里糊涂的用啊,于是找到了一篇好文章。全部看完,可以彻底搞清楚const的用法,如果只想了解某一部分,按红色标题找到对应部分看也行。

一、关于一般常量

声明或定义的格式如下:

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 isuninitialized 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 tothat 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 adouble; 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语言使用:double *ptr = (double*)&dVal;

2.const 指针(指针本身为常量)

声明或定义的格式如下(定义时必须初始化):

<类型说明符> *const <变量名> = ……

例如:

int errNumb = 0;

int iVal = 10;

int *const curErr = &errNumb;[curErr 是指向int 型对象的const指针]

指针的指向不能被修改。

curErr = &iVal; // error: curErr isconst

指针所指向的基础对象可以修改。

*curErr = 1; // ok:reset value of theobject(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 isconst

指针所指向的基础对象也不能被修改。

*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 &func2(); //注意千万不要返回局部对象的引用,否则会报运行时错误:因为一旦函数结束,局部对象被释放,函数返回值指向了一个对程序来说不再有效的内存空间。

返回指针:const int *func3(); //注意千万不要返回指向局部对象的指针,因为一旦函数结束,局部对象被释放,返回的指针变成了指向一个不再存在的对象的悬垂指针。

六、关于类

class A

{

public:

void func();

void func() const;

const Aoperator+(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)

2.修饰类成员函数

void func() const; // const成员函数中不允许对数据成员进行修改,如果修改,编译器将报错。如果某成员函数不需要对数据成员进行修改,最好将其声明为const成员函数,这将大大提高程序的健壮性。

const 为函数重载提供了一个参考

class A

{

public:

voidfunc();        // [1]:一个函数

void func() const; //[2]:上一个函数[1]的重载

……

};

A a(10);

a.func(); // 调用函数[1]

const A b(100);

b.func(); // 调用函数[2]

如何在const成员函数中对成员变量进行修改???

下面提供几种方式(只提倡使用第一种,其他方式不建议使用)

(1)标准方式:mutable

class A

{

public:

A::A(inti):m_data(i){}

void SetValue(int i){m_data = i; }

private:

mutable int m_data;// 这里处理

};

(2)强制转换:static_cast

class A

{

public:

A::A(inti):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(inti):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(inti):m_data(i){}

void SetValue(int i)

{ *m_data = i; } // 这里处理

private:

int *m_data;

};

(5)未定义的处理方式

class A

{

public:

A::A(inti):m_data(i){}

void SetValue(int i)

{ int *p =(int*)&m_data; *p = i } //这里处理

private:

int m_data;

};

注意:这里虽然说可以修改,但结果是未定义的,避免使用!

3.修饰类对象

const A a; // 类对象a只能调用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中
......
doublei=Pi;               file://此时为Pi分配内存,以后不再分配!
doubleI=PI;               file://编译期间进行宏替换,分配内存
doublej=Pi;               file://没有内存分配
doubleJ=PI;               file://再进行宏替换,又一次分配内存!

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

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

{

size = sz; //error:试图在构造函数体内对const成员变量进行初始化

}

C++const用法总结相关推荐

  1. php const用法详解

    php const用法详解 在编程中,我们一般用常量来定义那些在运行时不能被改变的常数值,下面让我们来看看php中的const吧,这个东西其 实没有什么好说的,只是为了知识的完善而随便说下吧.在定义一 ...

  2. C语言高频率--typedef和const用法详解

    一.typedef用法详解 C语言允许为一个数据类型起一个新的别名,就像给人起"绰号"一样. 起别名的目的不是为了提高程序运行效率,而是为了编码方便.例如有一个结构体的名字是 st ...

  3. C语言返回值是const类型,C++中const用法总结

    1.1.1. 定义普通常量 使用#define来定义常量也是常用方法,但const也可以用来定义常量,在[Effective C++]中建议使用const代替#define来定义常量,因为const定 ...

  4. 【C++】const 用法总结(非常实用)

    关键字 const 的用法在面试中出现的频率相当之高,但由于 const 用法非常多,时常遗忘,下面对 const 用法进行总结,算是做个笔记吧,方便日后学习!!! 1.const 用于定义常量 co ...

  5. C语言中const用法详解

    C语言中const用法详解 const修饰普通变量 const作用在于定义一个常量,比如const int a = 10,代表a的值不能被直接修改了,是一个常量,但仍可以通过指针的方式间接修改,如下图 ...

  6. typedef,static,const用法

    一.typedef主要功能是定义一个已存在类型的别名,但是和宏并存 宏与typedef区别 1.宏定义只是简单的字符串替换 2.typedef定义的类型是类型的别名,typedef后面是一个整体声明, ...

  7. C++ static与const用法详解

    目录 static的作用: 对普通变量: 1.局部变量: 2.全局变量 对类中变量: 1.成员变量 2.成员函数 const的作用: static的作用: 对普通变量: 1.局部变量: 在局部变量之前 ...

  8. java中finaljava中this_Java中this,static,final,const用法详解

    一.this 用类名定义一个变量的时候,定义的应该只是一个引用,外面可以通过这个引用来访问这个类里面的属性和方法,那们类里面是够也应该有一个引用来访问自己的属性和方法纳?JAVA提供了一个很好的东西, ...

  9. JS/ES6-var、let、const用法与区别

    目录 var的特点 1.作用域是全局作用域,没有块级作用域的概念 2.存在变量提升 let的特点 1.let声明的变量拥有块级作用域,let声明仍然保留了提升特性 2.let声明的全局变量不是全局对象 ...

  10. Const用法总结:Const,Const函数,Const变量,函数后面的Const (转)

    看到 const 关键字, C++ 程序员首先想到的可能是 const 常量.这可不是良好的条件反射.如果只知道用 const 定义常量,那么相当于把火药仅用于制作鞭炮. const 更大的魅力是它可 ...

最新文章

  1. java 计算运算表达式_java字符串运算表达式的计算
  2. 【他们都说 select * 不好,但是 。。。】
  3. linux c 通过 pid 获取 进程相关信息 cmdline
  4. Matrix 矩阵
  5. 写一个ajax程序就是如此简单
  6. 宽带651以及光猫红色灯闪烁-故障维修
  7. Java与.Net 在RSA加密方面能不能互相通讯操作???
  8. 大前端时代,从前端小工到架构师的进阶锦囊!
  9. 拼多多:不搞套路,要实现同品全网最低价直售
  10. 开源数据库:何为NoSQL生态系统?
  11. AutoCAD Eagle的常规操作和PCB制板及拼板说明
  12. 2020德勤面试开始了吗_刚去四大(德勤)面试,我只说了三个字,就拿到了offer!...
  13. 直播/点播系统快速搭建指南
  14. 基于toolbox_calib工具箱的相机标定matlab仿真
  15. mysql 赋权_《MySQL数据库》MySQL用户赋权
  16. window expects a time attribute for grouping in a stream environment.
  17. android 水滴动画效果图,Android控件实现水滴效果
  18. MySQL-pymysql模块
  19. 2023年EasyRecovery数据恢复还会收费吗?
  20. java记事本编译_Java记事本编译

热门文章

  1. PyTorch如何加载已经训练好的网络模型
  2. [SpringMVC笔记] SpringMVC-18-拦截器链配置
  3. steam搬砖项目,怎么做?详细解答
  4. Go 实现希尔排序算法及图解
  5. 流程图软件lauto_Iauto免费版下载|Iauto(流程图软件) v2.6.0官方版 - 万方软件下载站...
  6. Spring框架整合Java Web Token
  7. win10 22H2优化了大小核吗?
  8. 定制CRM系统如何整理各部门需求
  9. Python常用语句
  10. 计算机无法连接网络的原因主要有哪几种,电脑连不上网常见的几种处理方法