zoukankan      html  css  js  c++  java
  • 《Effective C++ 》学习笔记——条款03

    ***************************************转载请注明出处: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 )

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

    const std::vector<int>::iterator iter
    反之,迭代器能够指向不同的东西。但所指的内容不可修改:

    std::vector<int>::const_iterator iter

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

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

    ①函数的返回值

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

    ②函数的參数

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

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

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

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

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

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

    对于一个类,两个函数:

    class TextBlock
    {
    public:
        ....
        const char& operator[](std::size_t position)  const
        {  return text[position];  }
         char& operator[] ( std::size_t position )
        {  return text[position];  }
    private:
        std::string text;
    };

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

    std::cout<<tb[0];   // 没问题,读一个non-const
    tb[0] = ' x ';    // 没问题。写一个non-const
    std::cout<<ctb[0];    // 没问题,读一个const
    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測试。

    能够看以下这个样例:

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

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


    ——logical const 阵营

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

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

    class CTextBlock
    {
    public:
        ...
        std::size_t length() const;
    private:
        char* pText;
        std::size_t textLength;<span style="white-space:pre">	</span>// 近期一次计算的文本区块长度。
        bool lengthIsValid;<span style="white-space:pre">		</span>// 眼下长度是否有效
    };
    std::size_t CTextBlock::length() const
    {
        if( !lengthIsValid)
       {
            textLength = std::strlen( pText );<span style="white-space:pre">	</span>// 错误!

    在const 成员函数内不能赋值给这俩者 lengthIsValid = true; } return textLength; }


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

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

    class CTextBlock
    {
    public:
        ...
        std::size_t length() const;
    private:
        char* pText;
        mutable std::size_t textLength;	// 这些成员变量即使在
        mutable bool lengthIsValid;		// const成员函数内也可更改
    };
    
    std::size_t CTextBlock::length() const
    {
        if( !lengthIsValid)
       {
            textLength = std::strlen( pText );	// 如今能够这样
            lengthIsValid = true;
        }
        return textLength;
    }

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

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

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

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

    {

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

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

    }


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

    class TextBlock
    {
    public:
    	...
    	const char& operator[](std::size_t position) const
    	{
    	...
    	...
    	...
    	return text[position];
    	}
    	char& operator[](std::size_t position)
    	{
    		return
    			const_cast<char&>(
    			static_cast<const TextBlock&>(*this) [position]
    			);
    	}
    	...
    };

    这里用到了两个转型:

    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********************************************

  • 相关阅读:
    可自主二次开发的微信云控客服crm系统软件(带源码)
    个人微信号二次开发sdk协议,微信个人号开发API接口
    最新的微信SCRM客服系统
    微信个人号客服系统淘宝客发单机器人sdk服务端接口列表
    sdk定制开发微信群控云控客服系统教程
    web版微信自动发消息(实现微信个人号机器人)
    Adobe Audition 基本使用
    MPEG-7 视觉描述符
    图像检索:几种基于纹理特征的图像检索算法
    div+css基础教程
  • 原文地址:https://www.cnblogs.com/blfshiye/p/5164682.html
Copyright © 2011-2022 走看看