Effective C++读书笔记

Posted IIcyZhao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;  // 可以用来保存派生类指针

以上是关于Effective C++读书笔记的主要内容,如果未能解决你的问题,请参考以下文章

《Effective C++ 》学习笔记——条款11

effective c++学习笔记

读书笔记_Effective_C++_条款二十二:将成员变量声明为private

读书笔记_Effective_C++_条款十五:在资源类管理类中提供对原始资源的访问

读书笔记_Effective_C++_条款二十一:当必须返回对象时,别妄想返回其reference

读书笔记_Effective_C++_条款二十五: 考虑写出一个不抛出异常的swap函数