• 【Effective C++ 读书笔记】导读 Introduction


    学习程序语言根本大法是一回事,学习如何以某种语言设计并实现高效程序则是另一回事。

    一组明智选择并精心设计的classes、functions、templates可使程序编写容易、直观、高效、并且远离错误。

    带着问题去品读这本经验著作:

    设计上的讨论:
    “如何在两个不同的做法中择一完成某项任务?”

    • 选择继承(inheritance) or 模板(templates)?
    • 选择public继承还是private继承?
    • private继承还是composition(复合)?
    • 选择number函数还是non-number函数?
    • 选择pass-by-value还是pass-by-reference?

    即使完全知道该做什么,完全进入正轨可能还是可能有点棘手。

    • 什么是assignment操作符的适当返回类型(return type)?
    • 何时该令析构函数为virtual?
    • 当operator new无法找到合适的内存空间时该如何行事?

    榨出这些细节很重要,本书将带你趋凶避吉,避免那些未可预期、神秘难解的程序行为。

    软件设计和实现是复杂的差事,被硬件、操作系统、应用程序的约束条件涂上五颜六色,所以我能做的最好的就是提供指南,让你得以创造出更棒的程序。

    准则天生就带有例外。这就是为什么每个条款都有解释与说明。这些解释与说明是本书最重要的一部分。唯有了解条款背后的基本原理,你才能够决定是否将它套用于你所开发的软件,并奉行其所昭示的独特约束。

    本书的最佳用途:

    本书的最佳用途就是彻底了解 C++ 如何行为为什么那样行为以及如何运用其行为形成优势

    下面是每个C++程序员都应该了解的一份小小的 C++ 词汇。

    1. 声明式

      所谓声明式(declaration)是告诉编译器某个东西的名称和类型,但是略去细节。

          extern int x;       //对象声明式
          std::size_t numDigits(int number); //函数声明式
          class Widget;           //类声明式
      
          template<typename T>    //模板声明式
          class GraphNode;
    2. 签名式

      每个函数的声明揭示其签名式(signature),也就是参数和返回值类型。一个函数的签名就等同于该函数的类型。numDigits函数的签名是std::size_t (int),也就是说“这个函数获得一个int 并返回一个 std::size_t”。

    3. 定义式(definition)

      定义式的任务是提供编译器一些声明式所遗漏的细节。对对象而言,定义式是编译器为此对象拨发内存的地点
      对function 或者 function template 而言,定义式提供了代码本体。对 class 或者 class template 而言,定义式列出它的成员:

          int x;                     //对象定义式
          std::size_t numDigits(int number)  //函数定义式
          {
          //返回其参数的数字个数
              std::size_t digitsSoFar = 1;
              while ((number /= 10) != 0)
                  ++ digitsSoFar;
              return digitsSoFar;
          }
      
          class Widget                    //class 定义式
          {
              public:
              Widget();
              ~Widget();
              ...
          };
      
          template<typename T>            //template 的定义式
          class GraphNode{
              public:
              GraphNode();
              ~GraphNode();
              ...
          };
    4. 初始化(initialization)

      初始化(initialization)是“给予对象初值”的过程。对用户自定义类型的对象而言,初始化由构造函数执行。
      所谓default构造函数是一个可被调用而不带任何实参者。这样的构造函数
      要不没有参数要不就是每个参数都有缺省值

      class A{
          publicA();                        //default构造函数
      };
      
      class B{
          public:
          explicit B(int x = 0, bool b = true); //default构造函数
      }
      
      class C{
          public:
          explicit C(int x);          //不是default构造函数
      }

      上述的class B 和 C的构造函数都被声明为 explicit,这可阻止它们被用来执行隐式类型转换(implicit type conversions),但他们仍可被用来进行显示类型转换(explicit type conversions):

      void doSomething(B bobject);     //此函数接受一个类型为B的对象
      
      B bObj1;                         //一个类型为B的对象
      doSomething(bObj1);             //没问题,传递一个B给
                                      //doSomething函数
      
      B bObj2(28);                    //没问题,根据int 28 建立一个B
                                      //(函数的bool参数缺省为true)
      doSomething(28);                //错误!doSomething 应该接受
                                      //一个B,不是一个 int ,
                                      //int 和 B 之间没有隐式转换
      doSomething(B(28));             //没问题,使用 B 构造函数将 int 
                                      //显式转换为一个 B 以促成此调用

      被声明成 explicit 的构造函数禁止编译器执行非预期的类型转换。除非你有一个好理由允许构造函数被用于隐式类型转换,否则你应该把他声明为 explicit 。

    5. copy构造函数 和 copy assignment操作符

      copy构造函数被用来”以同类型对象初始化自我对象”
      copy assignment 操作符被用来“从另一个同类型对象中拷贝其值到自我对象”:

      class Widget{
          public:
          Widget();                             //default构造函数
          Widget(const Widget& rhs);            //copy构造函数
          Widget& operator=(const Widget& rhs); //copy assignment操作符
          ...
      };
      Widget w1;                               //调用default构造函数
      Widget w2(w1);                           //调用copy构造函数
      w1 = w2;                        //调用 copy assignment操作符

      当你看到赋值符号时请小心,因为“=”语法也可用来调用copy构造函数:

      Widget w3 = w2;              //调用copy构造函数

      如何区别是”copy构造”还是”copy赋值”:
      如果一个新对象被定义,一定会有一个构造函数被调用,不可能调用赋值操作。如果没有新对象被定义(例如前面的 “w1 = w2”语句),就不会有构造函数被调用,那么当然就是赋值操作被调用。

      copy构造函数是一个尤其重要的函数,因为他定义了一个对象如何 pass-by-value(以值传递)。
      举个例子:

      bool hasAcceptableQuality(Widget w);
      ...
      Widget aWidget;
      if (hasAcceptableQuality(aWidget)) ...

      参数w是以 by value 方式传递给 hasAcceptableQuality,所以在上述调用中 aWidget被复制到 w 体内。这个复制动作由 Widget 的copy构造函数完成。pass-by-value 意味“调用 copy 构造函数”。以 by value 传递用户自定义类型通常是个坏主意, Pass-by-Reference-to-const往往是比较好的选择。

    6. 未定义行为(Undefined behavior)[不明确行为]

      int* p = 0;               //p是一个null指针
      std::cout << *p;          //对一个null指针取值会导致不明确的行为
                                //null指针可读不可写
      
      char name[] = "Darla";    //name 是个数组,大小为6(别忘记最尾端的null)
      char c = name[10];          //只涉及一个无效的数组索引

  • 相关阅读:
    大数据平台的数据源
    大数据平台的数据采集
    kubernetes入门
    机器学习分类算法
    唱吧DevOps的落地,微服务CI/CD的范本技术解读
    JavaEE开发之SpringBoot整合MyBatis以及Thymeleaf模板引擎
    MySQL索引及查询优化总结 专题
    玩转spring boot——ajax跨域
    Linux Shell远程执行命令(命令行与脚本方式)
    Android ServiceConnection
  • 原文地址:https://www.cnblogs.com/lanqiu5ge/p/9472213.html
Copyright © 2020-2023  润新知