`
shi5jin
  • 浏览: 37388 次
  • 性别: Icon_minigender_1
  • 来自: 上海
最近访客 更多访客>>
社区版块
存档分类
最新评论

C++ 描述字之const (1)

阅读更多

        const可能是C++最受欢迎的描述字了。他提供了更好的安全语义。很多企业在面试的时候经常抛出诸如“请谈谈const的用法”之类的题目。

const描述字允许我们提供一个语义约束:声称其被描述的对象具有“不该被改动”的性质,令人感到兴奋的是,编译器会强制实施这项约束。同时,他也允许告诉编译器和其他程序员,某些值应该保持不变。const多才多艺,在许多语境下可以用到他:变量、指针、对象、参数、返回值甚至函数本身。现在把constC/C++中的用法作一个总结。

1C中的const

       C中的const主要用于描述变量、指针以及函数声明,我们一步步来。

1.1 变量

以下是const修饰变量时的常用用法:

cpp 代码
 
  1. const int SIZE = 1024;   
  2. const double PI = 3.1415926;  

<o:p></o:p>

       他为程序引入一个常量,以防止出现太多的“Magic Number”,同时也是为了能够方便的维护。在C中,我们也可以用#define来达到同样的目的:

cpp 代码
 
  1. #define SIZE 1024   
  2. #define PI 3.1415926  

不过其中存在一些微妙的区别,以至于我们强烈推荐使用const而不是#define来引入一个常量。原因如下:

       #define语句是一个预处理命令,他在编译器对源代码进行编译之前,就把所有的“名称”用“值”所替换了。所以,我们的程序中,其实并没有包括SIZEPI这样的字,而是10243.1415926,因此,也更加不会有SIZEPI的类型信息。所以,概括来说,用#define来引入常量有两点缺陷:

1.  我们所使用的名称没有被引入符号表(symbol table);

2.  他抛弃了名称的类型信息;

第一点会在调试、维护阶段添不少麻烦。可以说,用#define仅仅屏蔽了“开发期”的Magic Number。而第二点,部分的放弃了C++蕴含的严格的类型检查机制所带来的种种益处。综合考虑,我们强烈推荐在C/C++中用const替代#define

此外,还有一个传说中的“the enum hack”,用一个无名的enum来引入常量。其用法是:

<o:p> </o:p>
cpp 代码
 
  1. enum { SIZE = 1024, MAX = 4096 };  

    从某方面来讲,enum#define有些相似,有时候这是必须的。取enum或者#define常量的地址是不合法行为,但取const常量的地址就是合法的。如果你不想别人取得你常量的指针或者引用,同时你也不希望与#define带来的缺点进行某种“妥协”,那么enum会是一个很好的选择。我们应该认识enum hack的动力还来自于,很多现存的C++代码都大量的使用了这个技巧,我们应该认识他们。

1.2 指针

    指针从某方面来说也是一种变量,所以上一小节所述同样也适用。不过还是有两点要注意:

    首先指针蕴含两方面内容:指针本身以及所指对象,可以针对这两部分分别使用const描述字:

cpp 代码
 
  1. char greeting[] = “hello”;   
  2. char * p = greeting;              //non-const ptr, non-const data;   
  3. const char * p = greeting;        //non-const ptr, const data;   
  4. char * const p = greeting;        //const ptr, non-const data;   
  5. const char * const p = greeting;  //const ptr, const data;  

    同时,还应该注意到,const char *char const *并没有什么不同,个人习惯罢了。虽然变化多端,却并不高深莫测:星号右边的[1]const描述指针本身;星号左边的const描述所指对象。

    第二点,由于常量指针经常用于引入常量字符串,所以我们在头文件中经常看见上述用法。不过,这并不是一个好想法。如果我们的想法确实是引入字符串常量,请尝试使用:

<o:p> </o:p>
cpp 代码

 
  1. const std::string GREETING(“hello”);  
1.3
函数声明

    const最具威力的用法就是在函数声明时的应用。

    关于const参数,没有什么特别新颖的观念。唯一需要注意的就是,尽量在不会被修改的参数前面加上const。只不过多打6个字母,却可以在以后很长时间内,省下那些恼人的错误。这也是C++中为数不多的,很“便宜”的好处,尽量的使用吧!如果还想深入一点,就需要注意以下问题:由于种种原因[2],利用const来区分“需要改动”和“不需要改动”的参数,并不是一种“万能公式”。幸好,经过我们精心修改以后的“公式”,在大多数场合都是适用的:

1.  如果参数是内置类型,请使用Type *Type来加以区分;

2.  如果参数是用户自定类型,并且具有较复杂的构造-析构函数,请使用Type &  const Type &来加以区分;

关于返回值,也差不多这样:返回一个内置类型的时候,按值返回就好了;当返回一个用户自定义类型时,最好采用const Type。原因是:良好的自定义类型应该避免无端的与内置类型不兼容。而改动内置类型返回值是不合法的,所以,我们也最好为我们自己的类型提供这个“安全锁”。这样,往往可以降低因客户错误而造成的意外,而又不至于放弃安全性和高效性。

2.面向对象中的const

       这一章我们从前面一章的内容过渡到成员函数上,然后最后讨论以下有关bit constlogical const的相关概念。

2.1 过渡

       第一章的内容大部分都可以适用于这一章。但有两点需要注意:

       首先,关于常量初始化的问题。因为const变量一旦定义后即不可更改,所以在global域或者namespace[3]中使用const常量,通常(也必须)把声明和定义放在一起。在面向对象部分则不能这么干。因为类定义不可以对数据成员进行初始化(虽然有些编译器允许),所以就要另外找个地方对const数据成员进行初始化。构造函数?不。按照构造函数的语义,他是在已经“创造”了一个对象后,才进行的一些初始化操作。而按照用户自定义类中的常量语义,他应该在此之前就存在。所以应该(事实上也必须)在成员初始化列表中对数据常量进行定义。

cpp 代码
 
  1. class A {   
  2.   const int MAX_SIZE;   
  3.   int* arr;   
  4. public:   
  5.   A(void)    
  6.   : MAX_SIZE(1024),    
  7.     arr(new int [MAX_SIZE] ) {   
  8.     for(int i=0; i
  9.       arr[i] = i;   
  10.   }   
  11.   ~A() {}   
  12.   void print(void) {   
  13.   for(int i=0; i
  14.     std::cout << arr[i] << std::endl;   
  15.   }   
  16. };  

     这样做有着清晰却复杂的语法。所以另外一种妥协方式就是“the enum hack”:

 cpp 代码

 

 

 
  1. class A {   
  2.   enum { MAX_SIZE = 1024 };   
  3.   int* arr;   
  4. public:   
  5.   A(void)    
  6.   : arr(new int [MAX_SIZE] ) {   
  7.     for(int i=0; i
  8.       arr[i] = i;   
  9.   }
  10. …   
  11. };   

    简洁明了,这也是为什么现有代码大量使用这种技术的原因。不过他也有个显见的缺点:不能引入除整型以外其他类型的常量。

2.2 const成员函数

     const还可以修饰类的成员函数。

像函数参数一样,类的成员函数也可以划分两类:修改数据成员和不修改数据成员。当我们声明一个成员函数的时候,编译器会默认其为修改数据成员的函数,我们称这种为non-const成员函数(non-const member function),而与之对应的称为const成员函数(const member function)。同时,C++规定,对于用const声明的类对象如:

<o:p> </o:p>
cpp 代码
 
  1. const A test_A;  

    不能调用其non-const成员函数,而只能调用const成员函数。也就是说如果我们不采取一些措施来通知编译器,那么按默认规则,test_A将不能调用任何成员函数(构造和析构函数除外)。

cpp 代码
 
  1. const A test_A;   
  2. //Error!   
  3. //const object can not call non-const member function;   
  4. test_A.print();   

     改善C++程序效率的一个根本办法是以const Type &来传递对象,而这技术可行的前提是可以调用const对象的const成员函数。所以在设计类的成员函数的时候,我们就一定要明确区分那些是const成员函数,哪些是non-const成员函数,并且在const成员函数的参数列表和分号之间,使用const描述字,例如class A中:

 cpp 代码

 
  1. class A {   
  2.   …   
  3.   void print(voidconst {   
  4.     for(int i=0; i
  5.       std::cout << arr[i] << std::endl;   
  6.   }   
  7.   
  8. };   
  9.   
  10. int main(void) {   
  11.   const A test_A;   
  12.   test_A.print();  //OK!   
  13.   return 0;   
  14. }  

    同时注意,如果成员函数的常量性不同可以被重载。例如:

 cpp 代码

 
  1. class A {   
  2.   …   
  3.   void print(void){   
  4.   for(int i=0; i
  5.     std::cout << arr[i] << std::endl;   
  6.   }   
  7.   void print(voidconst {   
  8.   for(int i=0; i
  9.     std::cout << arr[i] << std::endl;   
  10.   }   
  11. };   
  12.   
  13. int main(void) {   
  14.   const A const_A;   
  15.   A non_const_A;   
  16.   const_A.print();      //const version print();   
  17.   non_const_A.print();  //non-const version print();   
  18.     
  19.   return 0;   
  20. }  



 

[1] 距离指针变量最近的,按照英语定语修饰习惯,应该是描述最直接的、关键的性质;较远的描述间接的、次要的性质。

[2] 为了不离题太远,这里就不具体说明了。

[3] global域或者namespace域:函数块、类块以外域。

分享到:
评论

相关推荐

    const 用法

    c++,const,描述const关键字在c++中的用法。

    算法设计与分析C++语言描述(陈慧南版)课后答案

    算法设计与分析C++语言描述(陈慧南版)课后答案知识点 一、最大公约数和循环次数 * 最大公约数为 1,快 1414 倍,主要考虑循环次数。 * 程序 1-2 的 while 循环体做了 10 次,程序 1-3 的 while 循环体做了 14141...

    C++语言const 关键字使用方法图文详解

    之前一直在学习C/C++,关于const的使用,这里出现一点,那里出现一点。知识用时方恨少,这一段时间正好各种笔试题,其中关于const的用法也是层出不穷,所以疲于在书本上各种翻,这里汇总一下,加深自己的印象的同时...

    C++中有关模板的试题题型练习题

    C++模板类型题型,更全面,也可以更从中了解模板的运用与技术。

    用C++实现DBSCAN聚类算法

    这几天由于工作需要,对DBSCAN聚类算法进行了C++的实现。时间复杂度O(n^2),主要花在算每个点领域内的点上。算法很简单,现共享大家参考,也希望有更多交流。 数据点类型描述如下: 代码如下:#include  using ...

    Effective C++ 中文版

    世界顶级C++大师Scott Meyers成名之作的第三版的确当得起这样的评价。当您读过《Effective C++中文版(第3版改善程序与设计的55个具体做法)》后,就获得了迅速提升自己C++功力的一个契机。  在国际上,本书所引起的...

    C++编程思想习题

    第1章 对象的演化 1.1基本概念 1.1.1对象:特性十行为 1.1.2继承:类型关系 1.1.3多态性 1.1.4操作概念:OOP程序像什么 1.2为什么C++会成功 1.2.1较好的C 1.2.2采用渐进的学习方式 1.2.3运行效率 1.2.4系统更容易...

    Effective C++

    书中的每一条准则描述了一个编写出更好的C++的方式,每一个条款的背后都有具体范例支持,书中讲的都是C++的编程技巧和注意事项,很多都是自己平时不太注意但又很重要的内容,绝对经典,作者Scott Meyers是全世界最...

    常见C++笔试题目整理(含答案).docx

    (1)const char *p:一个指向 char 类型的 const 对象指针,p 不是常量,我们可以修改 p 的值,使其指向不同的 char 对象。 (2)char const *p:同上。 (3)char * const p:此时*p 可以修改,而 p 不能修改。 (4)...

    C++复习资料之系列

    设X为整型变量,能正确表达数学关系1的C++逻辑表达式是( b, c, d )。 (a) 1(b) X==2||X==3||X==4 (c) 1(d) !(X&lt;=1)&&!(X&gt;=5) 26. 已知x=5,则执行语句 x += x -= x*x ; 后,x的值为( c )。 (a)25 (b)40 ...

    传智播客_C++基础课程讲义_v1.0.7(扫地僧)

    1、C++对C的扩展 1简单的C++程序 1.1求圆的周长和面积 数据描述: 半径,周长, 面积均用实型数表示 数据处理: 输入半径 r; 计算周长 = 2*π*r ; 计算面积 = π* r2 ; 输出半径,周长,面积; ...

    编译原理-语法分析实验(c++版)

    【问题描述】 请根据给定的文法设计并实现语法分析程序,能基于上次作业的词法分析程序所识别出的单词,识别出各类语法成分。输入输出及处理要求如下: (1)需按文法规则,用递归子程序法对文法中定义的所有种语法...

    C++的概念/解释,可打印,华南师范大学C++考过。

    1. 面向对象的三个基本特征 4 2. 抽象 4 3. 如何实现多态性 4 4. const与define的区别 4 5. static作用 4 6. 静态数据成员与静态成员函数 5 7. 静态数据成员与全局变量的不同 5 8. 为什么引入友元的概念? 5 9. 什么...

    摩托罗拉C++面试题

    11.结合1个你认为比较能体现OOP思想的项目,用UML来描述。(最好这个项目继承,多态,虚函数都有体现)这个问题大概会占面试时间的一半,并且会问很多问题,一不小心可能会被问住)。 。。。 12。基类的有1个虚函数...

    C++程序设计图书信息管理系统设计.doc

    //读者类,实现对读者的信息的描述 class Reader { private: //删除标记 1:已删 0:未删 int tag; //读者编号 int no; //读者姓名 char name[10]; //所借图书 int borbook[Maxbor]; public: Reader() { ...

    C++ String 类常用成员函数汇总

    C++ 的 String 类提供了多种成员函数来操作字符串,这些成员函数可以分为构造函数、字符操作、特性描述、输入输出操作和赋值五大类。 首先,String 类的构造函数有多种重载版本,这些构造函数可以用来初始化字符串...

    C/C++笔试题(附答案,华为面试题系列)

    (1)不调用C++/C 的字符串库函数,请编写函数 strcat 答: VC源码: char * __cdecl strcat (char * dst, const char * src) { char * cp = dst; while( *cp ) cp++; /* find end of dst */ while( *cp++ = *src++ ...

    C/C++招聘考试题目.rar

    void DivideString(const char *pInputStr, long lInputLen, char *pOutputStr); 【输入】 pInputStr: 输入字符串 lInputLen: 输入字符串长度 【输出】 pOutputStr: 输出字符串,空间已经开辟好,与输入字符串...

    图书馆信息管理系统(C++)

    //读者类,实现对读者的信息的描述 class Reader { private: int tag; //删除标记 1:已删 0:未删 int no; //读者编号 char name[10]; //读者姓名 int borbook[Maxbor];//所借图书 public: Reader() {} char *...

    C++语言实现线性表之数组实例

    本文实例讲述了C++语言实现线性表之数组。分享给大家供大家参考。具体分析如下: 感觉用C++中的构造函数、析构函数等类的特点来描述一些数据结构更加易读,更加合理,便捷。但有一个问题,编译器不支持模板的分离...

Global site tag (gtag.js) - Google Analytics