`
shi5jin
  • 浏览: 38042 次
  • 性别: 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域:函数块、类块以外域。

分享到:
评论

相关推荐

    数据结构习题解析-面向对象方法和C++语言描述-殷人昆.pdf

    数据是信息的载体,是描述客观事物的数、字符、符号的集合,可以是数字、文字、图像等各种形式。信息则是数据在人们头脑中的反映,是对现实世界事物的理解和认知。数据是信息的基础,而信息是对数据的解读和处理后的...

    数据结构C++语言描述

    通过阅读“数据结构C++语言描述.pdf”这本书,读者可以深入学习这些概念,并通过实践加深理解。 总之,数据结构是编程的基础,而C++作为一门强大的编程语言,为我们提供了丰富的工具来实现和操作这些结构。熟练掌握...

    一个c++描述的栈类

    ### 一个C++描述的栈类 #### 概述 本文档介绍了一个使用C++编写的通用栈类的实现。该栈类通过模板机制支持多种数据类型,并且提供了丰富的功能来管理和操作栈内的数据。栈是一种后进先出(Last In, First Out, LIFO...

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

    《C++语言const关键字使用方法图文详解》 在C++编程中,`const`关键字扮演着重要的角色,它用于定义常量和限定变量的可变性。...正确理解和使用`const`能够提升程序的安全性和效率,也是C++程序员必备的基本技能之一。

    Effective C++ 中文版第三版 高清PDF.pdf

    - 描述了如何正确使用const关键字,包括const成员函数和const参数,以及const和非const指针的区别。 - 解释了引用作为函数参数和返回值的优势,以及如何避免引用未初始化的问题。 4. **运算符重载**: - 讨论了...

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

    函数模板是C++模板技术的核心组件之一,它允许开发者定义泛型函数,以便在不同的数据类型上实现相同的操作。实验中,要求设计一个函数模板sort,采用选择法排序方式对数据进行降序排序。sort函数模板的设计方法可以...

    用C++语言描述分数类,并进行各种运算

    在C++编程中,设计一个...总之,用C++描述分数类并进行各种运算涉及类的定义、成员变量、构造函数、运算符重载以及友元函数等多个C++核心概念。通过这样的实现,我们可以有效地处理分数,使代码更加模块化和易于维护。

    C++ 面经 (1) 答案

    在本例中,`TestSFunc1`函数的参数`obj`被声明为`const SBASET*`类型,这意味着通过`obj`只能访问`SBASET`类及其派生类中的`const`成员。这是理解为什么`TestSFunc1`函数内部调用`obj-&gt;fool()`时会调用到基类的`fool...

    数据结构(C++描述)--复数类

    总结来说,这个“数据结构(C++描述)--复数类”的项目展示了如何在C++中利用面向对象编程来实现复数的数学运算,包括加减乘除以及输入输出操作。这不仅加深了对C++语言的理解,也强化了数据结构和算法的应用能力,...

    数据结构与算法分析 C++描述

    ### 数据结构与算法分析 C++描述 #### 一、引言与重要性 在软件开发领域,掌握数据结构和算法是构建高效、可维护及可靠软件系统的关键。本篇文章将根据给定的文件内容,深入探讨《数据结构与算法分析 C++描述》一...

    Effective_C++_3rd_Edition.pdf 英文原版

    1. 视C++为语言联邦:Scott Meyers提出了一个概念,即C++是由若干个相对独立的语言子集组成的,包括C语言、面向对象的C++和模板C++。理解这种多语言属性有助于更好地掌握C++的复杂性和灵活性。 2. 使用const替代#...

    c++primer中文版勘误表

    16. P65 1 行错误:word(字)机器上的自然的整型计算单元更正:word(字)是在给定机器上进行整型计算的自然单元 知识点:这里的修订是为了使语言更加准确和通俗。在 C++ 中,word 是一种基本数据类型,而这里的...

    c++编程小题目

    根据给定文件中的四个C++小题目,我们可以逐一分析这些代码背后的逻辑以及它们解决的问题。 ### 第一个小题目 **题目描述:** 一个球从100米高度自由落下,每次落地后反跳回原高度的一半;再落下,求它在第10次...

    C++基础C++相关笔记总结

    根据给定的文件信息,以下是对C++基础知识的详细总结,涵盖了标题与描述中的关键知识点,包括虚函数、常量成员函数、构造函数、析构函数、模板等核心概念。 ### 虚函数与常量成员函数 在C++中,虚函数允许派生类...

    C++语言编程规范pdf,c++语言编程规范 华为,C,C++

    - 变量名、函数名、类名等应清晰、简洁且具有描述性,避免使用缩写和无意义的字符。 - 类名首字母大写,如`ClassName`;变量和函数名小写,单词间用下划线连接,如`variable_name`或`function_name`。 - 常量命名...

    C++ 14标准草案

    - **国际标准结构**:描述了整个C++ 14标准文档的组织结构。 - **语法表示法**:解释了C++ 14标准中使用的语法表示方法。 - **C++内存模型**:详细介绍了C++中的内存管理机制,包括内存分配、释放、同步等。 - **C++...

Global site tag (gtag.js) - Google Analytics