Effective C++读书笔记

【条款01】 视C++为一个语言联邦

                   ① C语言部分 ② Object-Oriented C++ ③ Template C++泛型编程 ④ STL :容器、迭代器、算法、函数对象

                    高效的传值方式: pass-by-value对于内置类型 和 (迭代器、函数对象)[指针实现]

                                                  pass-by-reference对于用户自定义类来说比较高效,pass-by-value的时候会调用复制构造函数。

 

【条款02】 尽量以const, enum, inline 代替 #define

                #define定义常量容易被编译器处理掉并未进入符号表,不会有类型检查,当出现错误时报字面信息,不容易定位;而且不能定义局部常量, 定义函数容易出现副作用  (尽量用template<typename T> inline 函数代替#define定义函数,有类型检查且不会有副作用)。

                用const可以定义常量,有类型检查,可以定义在scope中。

                const static 类型在类中编译器可能不支持初值, 可以用 enum常量来mock,解决这个问题,如下:

                class GamePlayer {

                  private:

                   enum { NumTurns = 5};

                   int scores[NumTurns];

                };

 

【条款03】 尽可能的使用const

        (const可以指定一个语义约束,指明哪些对象是不能被改变的)

        1. const指针

            char[] str= “hello”;

            char* p = str;     // non-const pointer; non-const data

            const char * p = str;  //non-const pointer; const data

            char const * p = str;  //non-const pointer; const data

            char * const p = str; //const pointer, non-const data

            const char * const p = str; // const pointer, const data

           const出现在星号左边时,指针指向的内存内容不可变,但可以指向其它对象的地址;const出现在星号的右边时,指针不可改变其指向,但可以改变内容;const出现在星号左右两边时,其指向和内容都不可以改变。

       2. const迭代器

          vector<int> vec;

          const vector<int>::iterator iter = vec.begin(); //不能改变iter的指向,但可以更改其内容;相当于 char* const p

          const vector<int>::const_iterator iter = vec.begin(); //可以改变其指向,但不可以改变其内容; 相当于 const char* p

       3.函数返回值设为const对象, 可以防止函数返回值被另修改

          const Object operator*(const Object& lhs, const Object& rhs);

          Object a, b, c;

          a * b = c;  // 若返回值不为const类型,返回结果就会被c覆盖;返回const类型后则会报错

          if (a*b == c)  // 若误写为 if(a*b = c)同样会报错

       4.const成员函数

         该成员函数可作用于const对象之上,类的成员函数后面加 const,表明这个函数不会对这个类对象的数据成员(准确地说是非静态数据成员)作任何改变。
        在设计类的时候,一个原则就是对于不改变数据成员的成员函数都要在后面加 const,而对于改变数据成员的成员函数不能加 const。所以 const 关键字对成员函数的行为作了更加明确的限定:有 const 修饰的成员函数(指 const 放在函数参数表的后面,而不是在函数前面或者参数表内),只能读取数据成员,不能改变数据成员;没有 const 修饰的成员函数,对数据成员则是可读可写的。
        除此之外,在类的成员函数后面加 const 还有什么好处呢?那就是常量(即 const)对象可以调用const 成员函数,而不能调用非const修饰的函数。正如非const类型的数据可以给const类型的变量赋值一样,反之则不成立。

         两个成员函数如果只是常量性不同,可以被重载。

         如string类型的[]操作符就有const和non-const两种,const型返回const char&,非const型返回char&;

         当const和non-const成员函数有着实质的等价实现时,另non-const版本调用const版本,可以简化代码实现。

         在const成员函数中不可调用non-const成员函数,const函数不能改变non-const成员变量的值,如在其中调用non-const函数则可能改变成员变量的值。

         因此,由non-const成员函数调用const成员函数,不存在限制条件。 但若两个函数仅仅是采用const型的重载,在non-const调用const实现时,需要用static_cast对this指针的对象强制转换为const类型对象来调用const成员函数,否则就是non-const成员函数自己调用自己,是死循环。

        static_cast<const Object>(*this).func();若const函数返回值为const类型,non-const函数返回值为non-const类型,则需要用const_cast对const对象的返回值进行去const转换,然后再作为non-const函数的返回值返回。

        return const_cast<R&> ( static_cast<const Object&>(*this).func());    

 

【条款04】 确定对象被使用前被初始化

        c part-of-C++为保证效率,不确保其内容已被初始化,如array; 而STL来自part-of-C++则保证其内容被初始化了。

        因此,要慎重处理,必须永远保证使用对象之前将其初始化。 内置成员变量必须手动初始化。 

       保证类的每个构造函数都将对象的每一个成员初始化。

 

 

【条款20】 宁以pass-by-reference-to-const 替换 pass-by-value

      pass-by-value传参会调用类的构造函数生成对象副本,结束时还要调用析构函数销毁临时副本,这都大大增加了开销。

      pass-by-reference-to-const实质上是传递的对象指针,不会有临时对象生成,没有相应的构造和析构开销。

      对象切割问题:当形参为基类对象,实参为派生类对象以pass-by-value方式传入时,仅会调用基类的copy构造函数生成临时对象,派生类的特质部分全被切割掉了。

      若想传入不同派生类的对象,则应使用基类的指针或引用,即pass-by-reference 或 pass-by-pointer方式,为防止传入对象被修改,应采用const修饰。

     同理,由于容器内保存的也是调用类的copy-ctor函数生成的临时对象, 若想在同一容器内保存不同派生类对象时,也需要保存派生类对象的指针,否则也会产生对象切割问题  。     如 vector<Base> vec; // error              vector<Base*> vec;  // 可以用来保存派生类指针

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值