堕_落羽吧 关注:16贴子:786
  • 11回复贴,共1

《Effective C++》 学习笔记

只看楼主收藏回复

01:将C++视为一个语言集合
C++中主要的次语言有4个:
(1)C。说到底 C++ 仍是以 C 为基础。 区块 (blocks) 、语句(statements) 、预处理器 (preprocessor) 、 内置数据类型 (built-in data types) 、数组 (arrays) 、指针 (pointers) 等统统来自C。C 语言的局限:没有模板(templates), 没有异常 (exceptions) , 没有重载 (overloading) ……
(2)Object-OrientedC++。这部分也就是 C with Classes所诉求的: classes (包括构造函数和析构函数), 封装 (encapsulation) 、继承 (inheritance) 、多态(polymorphism) 、 virtual 函数(动态绑定)……等等。这一部分是面向对象设计之古典守则在 C++ 上的最直接实施。
(3)Template C++。这是 C++的泛型编程 (generic programming) 部分, 也是大多数程序员经验最少的部分。 Template 相关考虑与设计已经弥漫整个 C++, 良好 编程守则中 “惟template 适用 ” 的特殊条款并不罕见(例如条款 46 谈到调用 template functions 时如何协助类型转换)。实际上由于templates威力强大, 它们带来崭新的编程范型 (programming paradigm) , 也就是所谓的 template metaprogramming (TMP, 模板元编程)。条款48 对此提供了一份概述,但除非你是 template 激进团队的中坚骨干, 大可不必太担心这些。 TMP 相关规则很 少与C廿主流编程互相影响。
(4)STL。 STL 是个 template 程序库, 看名称也知道,但它是非常特殊的一个。 它对容器 (containers)、迭代器 (iterators) 、算法(algorithms) 以及函数对象 (function objects) 的规约有极佳的紧密配合与协调, 然而 templates 及程序库也可以其他想法建置出来。 STL有自己特殊的办事方式, 当你伙同 STL 一起工作, 你必须遵守它的规约。


IP属地:广东1楼2022-09-07 21:46回复
    02:尽量以 const, enum, inline 替换 #define
    (1)对于单纯常量,最好以const对象或enums替换#defines。
    例如 #defineASPECT_RATIO 1. 653
    记号名称ASPECT_RATIO也许从未被编译器看见;也许在编译器开始处理源码之前它就被预处理器移走了,于是记号有可能没进入记号表(symbol table)内,于是当你运用此常量但获得一个编译错误信息时,可能会带来困惑,因为这个错误信息也许会提到1.653而不是ASPECT_RATIO,于是你将因为追踪它而浪费时间。
    解决之道是以一个常量替换上述的宏(#define):
    const double AspectRatio = 1.653;
    (2)对于形似函数的宏(macros), 最好改用inline函数替换#defines。
    例如 #defineCALL_WITH_MAX(a, b) f((a) > (b) ? (a) ; (b))
    这般长相的宏有着太多缺点,光是想到它们就让人痛苦不堪。无论何时当你写出这种宏,你必须记住为宏中的所有实参加上小括号,否则某些人在表达式中调用这个宏时可能会遭遇麻烦。但纵使你为所有实参加上小括号,看看下面不可思议的事情:
    int a = 5, b = 0;
    CALL WITH MAX (++a, b); //a被累加二次
    CALL WITH MAX (++a, b + 10); //a被累加一次
    在这里,调用f之前,a的递增次数竟然取决于 “ 它被拿来和谁比较"。
    解决方法为使用templateinline函数:
    template<typename T> //由于我们不知道
    inline void callWithMax(constT& a, const T& b) { //T是什么,所以采用
    f(a > b? a : b); //pass by reference-to-const.
    } //见条款20.


    IP属地:广东2楼2022-09-07 21:46
    回复
      2025-11-07 05:02:50
      广告
      不感兴趣
      开通SVIP免广告
      03:尽可能使用const
      (1)将某些东西声明为const 可帮助编译器侦测出错误用法。const 可被施加于任何作用域内的对象、函数参数、函数返回类型、成员函数本体。


      IP属地:广东3楼2022-09-07 21:47
      回复


        IP属地:广东4楼2022-09-07 21:48
        回复
          (2)编译器强制实施bitwise constness,但你编写程序时应该使用”概念上的常量性”(conceptual constness) 。
          (3)当 const 和 non-const 成员函数有着实质等价的实现时,令 non-const 版本调用 const 版本可避免代码重复。


          IP属地:广东6楼2022-09-07 21:50
          回复
            04:确定对象被使用前已先被初始化
            (1)为内置型对象进行手工初始化,因为C++不保证初始化它们。
            关于“将对象初始化”这事, C++ 似乎反复无常。如果你这么写:
            int x;
            在某些语境下 x 保证被初始化(为0),但在其他语境中却不保证。如果你这么写:
            class Point {
            int x, y;
            };
            ...
            Point p;
            p 的成员变址有时候被初始化(为0),有时候不会。
            读取未初始化的值会导致不明确的行为。


            IP属地:广东7楼2022-09-07 22:00
            回复
              (2)构造函数最好使用成员初值列(member initialization list) ,而不要在构造函数本体内使用赋值操作(assignment) 。初值列列出的成员变量,其排列次序应该和它们在class 中的声明次序相同。


              IP属地:广东8楼2022-09-07 22:01
              回复
                考虑一个用来表现通讯簿的class, 其构造函数如下:


                IP属地:广东9楼2022-09-07 22:01
                回复
                  2025-11-07 04:56:50
                  广告
                  不感兴趣
                  开通SVIP免广告
                  这会导致ABEntry 对象带有你期望(你指定)的值,但不是最佳做法。C++ 规定,对象的成员变量的初始化动作发生在进入构造函数本体之前。在ABEntry 构造函数内, theName, theAddress 和thePhones 都不是被初始化,而是被赋值。初始化的发生时间更早,发生于这些成员的default 构造函数被自动调用之时(比进入ABEntry 构造函数本体的时间更早) 。但这对 numTimesConsulted 不为真,因为它属于内置类型,不保证一定在你所看到的那个赋值动作的时间点之前获得初值。


                  IP属地:广东10楼2022-09-07 22:02
                  回复
                    ABEntry 构造函数的一个较佳写法是,使用所谓的member initialization list(成员初值列)替换赋值动作:


                    IP属地:广东11楼2022-09-07 22:03
                    回复
                      这个构造函数和上一个的最终结果相同,但通常效率较高,因为前者先调用default 构造函数然后再调用copyassignment操作符,后者只调用一次copy 构造函数。对于内置型对象如numTimesConsulted, 其初始化和赋值的成本相同,但为了一致性最好也通过成员初值列来初始化。同样道理,甚至当你想要default 构造一个成员变量,你都可以使用成员初值列,只要指定无物(nothing) 作为初始化实参即可。假设ABEntry有一个无参数构造函数,我们可将它实现如下:


                      IP属地:广东12楼2022-09-07 22:04
                      回复
                        (3)为免除“跨编译单元之初始化次序” 问题,请以localstatic 对象替换non-local static 对象。


                        IP属地:广东13楼2022-09-07 22:04
                        回复