***************************************转载请注明出处:http://blog.csdn.net/lttree********************************************

一、 Accustoming Yourself to C++

Rule 03: Use const whenever possible.

条款03:尽可能的使用const

const就是常量,它同意你指定一个语义约束,编译器会强制实施这项约束。

多才多艺的keywordconst 有多种用途:

① 在classes 外部修饰global 或 namespace 作用域中的常量

② 修饰文件、函数 或 区块作用域(block scope )中被声明为static的对象

③ 用它修饰classes内部的 static 和 non-static 成员变量

几个关键的数据

1.对于指针

对于指针,能够设定 指针自身 、 指针所指物 或 两者都是(或都不是) const

分辨方法也非常easy:假设const出如今星号(*)左面,表示被指针所指的物是常量。假设出如今右面,表示指针自身是常量。

自此。也能够扩展到 迭代器 ( iterator )

假设你想表示这个迭代器不得指向不同的东西,但它所指的东西的内容是能够修改的:

  1. const std::vector<int>::iterator iter

反之,迭代器能够指向不同的东西。但所指的内容不可修改:

  1. std::vector<int>::const_iterator iter

2.最具威力的使用方法——对于函数声明时的应用

在一个函数声明中,const 能够和 函数返回值、各參数、函数自身 产生关联。

①函数的返回值

令函数返回一个常量值,往往能够减少因客户错误而造成的意外。而又不至于放弃安全性和高效性。

②函数的參数

除非你有须要修改參数或local const对象,否则请将它们声明为const。只几个字符,能够帮你省下非常多的烦恼。

③函数自身(const成员函数)

const实施于成员函数的理由有两个:

<1> 它们使classes接口比較easy理解(能够明白知道哪个函数能够修改对象内容。而哪个不能)

<2> 它们使“操作const对象”成为可能。 这个是 "pass by reference to const 方式传递对象"技术的基础。

并且,在重载方面,另一个非常重要的特性。

对于一个类,两个函数:

  1. class TextBlock
  2. {
  3. public:
  4. ....
  5. const char& operator[](std::size_t position) const
  6. { return text[position]; }
  7. char& operator[] ( std::size_t position )
  8. { return text[position]; }
  9. private:
  10. std::string text;
  11. };

仅仅要重载 operator[] 并对不同的版本号给予不同的返回类型,就能够令 const 和 non-const TextBlocks 获得不同的处理:

  1. std::cout<<tb[0]; // 没问题,读一个non-const
  2. tb[0] = ' x '; // 没问题。写一个non-const
  3. std::cout<<ctb[0]; // 没问题,读一个const
  4. ctb[0] = ' x '; // 错误,写一个const

错误的原因是  企图对一个“由const版之operator[]返回”的const char& 施行赋值动作。

此处要注意一下 non-const operator[] 的返回类型是个 reference to char (引用char型),不是char,

否则 tb[0] = ' x '将无法通过编译。

对于 成员函数假设是const意味性 有两个流派:bitwise 和 logical

——bitwise const 阵营

奉行: 成员函数仅仅有在不更改对象之不论什么成员变量(static除外)时才干够说是const。也就是说它不更改对象内的不论什么一个bit(位)。

长处:非常easy侦測违反点,编译器仅仅须要寻找成员变量的赋值动作就可以。

不足:不幸的是很多成员函数尽管不十足具备const性质却能通过bitwise測试。

能够看以下这个样例:

  1. const CTextBlock cctb("Hello");
  2. char* pc = &cctb[0];
  3. *pc = 'J';

这样cctb如今存储的是 "Jello"这个内容,显然不符合const的定义

——logical const 阵营

奉行:一个const成员函数能够改动它所处理的对象内的某些bits,但仅仅有在client监測不出的情况下才如此。

比如 你的CTextBlock class 有可能快速缓存(cache)文本区块的长度以便询问:

  1. class CTextBlock
  2. {
  3. public:
  4. ...
  5. std::size_t length() const;
  6. private:
  7. char* pText;
  8. std::size_t textLength;<span style="white-space:pre"> </span>// 近期一次计算的文本区块长度。
  9. bool lengthIsValid;<span style="white-space:pre"> </span>// 眼下长度是否有效
  10. };
  11. std::size_t CTextBlock::length() const
  12. {
  13. if( !lengthIsValid)
  14. {
  15. textLength = std::strlen( pText );<span style="white-space:pre"> </span>// 错误!
  16.  
  17. const 成员函数内不能赋值给这俩者
  18. lengthIsValid = true;
  19. }
  20. return textLength;
  21. }

length实现肯定不是 bitwise const 。由于textLength 和 lengthIsValid都可能被改动。它们两者被改动对const CTextBlock 对象而言尽管能够接受。但编译器不允许。

所以就用一个mutable(可变的)来解决,用mutable来释放掉non-static 成员变量的bitwise constness约束

  1. class CTextBlock
  2. {
  3. public:
  4. ...
  5. std::size_t length() const;
  6. private:
  7. char* pText;
  8. mutable std::size_t textLength; // 这些成员变量即使在
  9. mutable bool lengthIsValid; // const成员函数内也可更改
  10. };
  11.  
  12. std::size_t CTextBlock::length() const
  13. {
  14. if( !lengthIsValid)
  15. {
  16. textLength = std::strlen( pText ); // 如今能够这样
  17. lengthIsValid = true;
  18. }
  19. return textLength;
  20. }

So 在const 和 non-const成员函数中避免反复

这个问题是由上面问题产生的,mutable固然能够解决变量的问题,可是假设这个东西非常长,

我们则须要些两份非常长非常长的怪物,so scary!

这就须要non-const来调用const的东西来避免反复,这样修改也方便一些,

{

为什么不让const调用non-const的?

拜托,const成员函数承诺绝不改变其对象的逻辑状态,non-const没有

}

这样就须要 调用 转型 这个概念,看以下的样例:

  1. class TextBlock
  2. {
  3. public:
  4. ...
  5. const char& operator[](std::size_t position) const
  6. {
  7. ...
  8. ...
  9. ...
  10. return text[position];
  11. }
  12. char& operator[](std::size_t position)
  13. {
  14. return
  15. const_cast<char&>(
  16. static_cast<const TextBlock&>(*this) [position]
  17. );
  18. }
  19. ...
  20. };

这里用到了两个转型:

static_cast     将non-const对象转换成const对象

const_cast     移除const

结束语:

const是一个很奇异的且非比平常的东西,

它能够用在 指针和迭代器上;

在指针、迭代器及reference指涉的对象身上;

在函数參数和返回类型上;

在local变量身上;

在成员函数身上,

等等。。

。。

Please remember:

<1> 将某些东西声明为 const 可帮助编译器侦測出错误使用方法。const可被施加于不论什么作用域内的对象、函数參数、函数返回类型、成员函数本体。

<2> 编译器强制实施bitwise constness。但你编敲代码时应该使用 conceptual constness(概念上的常量性)。

<3> 当const和non-const 成员函数有着实质等价的实现时,令non-const版本号用const版本号可避免代码反复。

***************************************转载请注明出处:http://blog.csdn.net/lttree********************************************

《Effective C++ 》学习笔记——条款03的更多相关文章

  1. Effective C++学习笔记 条款07:为多态基类声明virtual析构函数

    一.C++明确指出:当derived class对象经由一个base class指针被删除,而该base class带着一个non-virtual析构函数,其结果未定义——实际执行时通常发生的是对象的 ...

  2. Effective C++学习笔记 条款06:如不想使用编译器自动生成的函数,就该明确拒绝

    一.为驳回编译器自动提供的机能,可将相应成员函数声明为private并且不予实现.(如果你仅仅是自己不实现的话,编译器会帮你实现) 如: class A { public: A(const strin ...

  3. Effective C++学习笔记 条款05:了解C++默默编写并调用的哪些函数

    一.如果用户没有提供构造函数.copy构造函数.copy assignment操作符和析构函数,当且仅当这些函数被需要的时候,编译器才会帮你创建出来.编译器生成的这些函数都是public且inline ...

  4. Effective C++学习笔记 条款04:确定对象被使用前已先被初始化

    一.为内置类型对象进行手工初始化,因为C++不保证初始化它们. 二.对象初始化数据成员是在进入构造函数用户编写代码前完成,要想对数据成员指定初始化值,那就必须使用初始化列表. class A { pu ...

  5. Effective C++学习笔记 条款02:尽量以const,enum,inline替换 #define

    尽量使用const替换 #define定义常量的原因: #define 不被视为语言的一部分 宏定义的常量,预处理器只是盲目的将宏名称替换为其的常量值,导致目标码中出现多分对应的常量,而const定义 ...

  6. Effective STL 学习笔记 39 ~ 41

    Effective STL 学习笔记 39 ~ 41 */--> div.org-src-container { font-size: 85%; font-family: monospace; ...

  7. Effective STL 学习笔记 Item 38 : Design functor classes for pass-by-value

    Effective STL 学习笔记 Item 38 : Design functor classes for pass-by-value */--> div.org-src-container ...

  8. Effective STL 学习笔记 Item 34: 了解哪些算法希望输入有序数据

    Effective STL 学习笔记 Item 34: 了解哪些算法希望输入有序数据 */--> div.org-src-container { font-size: 85%; font-fam ...

  9. Effective STL 学习笔记 32 ~ 33

    Effective STL 学习笔记 32 ~ 33 */--> div.org-src-container { font-size: 85%; font-family: monospace; ...

随机推荐

  1. 【转】android 电容屏(三):驱动调试之驱动程序分析篇

    关键词:android  电容屏 tp 工作队列 中断 坐点计算  电容屏主要参数平台信息:内核:linux2.6/linux3.0系统:android/android4.0  平台:S5PV310( ...

  2. magento添加系统sections配置时应注意的事项

    (1)只有在新增sections是需要增加对应的acl配置,这个配置可以放在config.xml中或者放在adminhtml.xml中 <adminhtml> <acl> &l ...

  3. Unity Scene为每一个游戏物体进行扩展编辑

    2个月前还在忙碌的找实习工作,看见招聘信息上面有一条熟悉扩展Unity编辑器,配合美工编程. 自己动手写完这个代码时候,发现写代码就像弹钢琴多么神奇. TestEdit类: using UnityEn ...

  4. Change the ball(找规律)

    Change the ball Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)T ...

  5. 怎样给你的Android 安装文件(APK)减肥

    转自: http://greenrobot.me/devpost/putting-your-apks-on-diet/ Android的apk文件越来越大了这已经是一个不争的事实. 在Android ...

  6. UVA 246 - 10-20-30 (模拟+STL)

    UVA 246 - 10-20-30 题目链接 题意:给52张的扑克堆,先从左往右发7张牌,之后连续不断从左往右发7张牌,假设有牌堆形成了下面3种情况(按顺序推断): 1.头两张+尾一张和为10或20 ...

  7. 【数学.前左上计数法】【HDU1220】Cube

    Cube Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submi ...

  8. JavaScript类的设计

    [转载] Javascript与其他的面向对象语言不同,如C++,Java或PHP等.它并不是基于类的,而是基于原型的一种语言. 1.对象创建 在Javascript中创建一个类是非常容易的: var ...

  9. C#自定义控件在添加引用后不显示在工具箱的解决方法

    先说一些背景: 在开发C#项目时,发现很多控件存在复用的情况,控件的属性都是要设置成一样的,我就想,能不能设置一个类来存放这个控件,这样我每次用的时候直接加一些特殊的操作就可以了,不需要再次设置控件属 ...

  10. SQL语言学习-数据操纵语言

    一般而言,数据库中数据的生命周期包括数据插入以及更新.数据删除3个阶段.首先需要用户或者系统将数据插入表.然后,对数据的使用,包括数据的检索以及数据的更新.最后,如果数据已经没有使用价值,则将数据删除 ...