• Effective C++ 第二章


    2. Constructors, Destructors, and Assignment Operators 构造/析构/赋值运算

    05: Know what functions C++ silently writes and calls

    了解C++默默编写并调用哪些函数

    • 编译器可以暗自为class创建默认构造函数、复制构造函数、赋值运算操作符和析构函数
      空类(empty class)不是真正的空类,当有需要被调用以上函数时,编译器会默认创建

      class Empty { };
      // 相当于
      class Empty {
      public:
      	Empty() { ... }
      	Empty(const Empty& rhs) { ... }
      	~Emtpy( ) { ... }
      	Empty& operator=(const Empty& rhs) { ... }
      };
      

    06: Explicitly disallow the use of compiler-generated functions you do not want

    若不想使用编译器自动生成的函数,就该明确拒绝

    • 希望设计的类不支持以下操作

      HomeForSale h1;
      HomeForSale h2;
      HomeForSale h3(h1); // 不能通过编译
      h2 = h1;			// 也不能通过编译
      
    • 将拷贝构造函数、赋值运算操作符声明为private,阻止了编译器默认创建public版本
      并不绝对安全,无法阻止成员函数和友元函数调用

    • 将成员函数声明为private且不实现,如C++ iostream的设计

      class HomeForSale {
      public:
      		...
      private:
      	HomeForSale(const HomeForSale&);			// 只有声明,没有定义
      	HomeForSale& operator=(const HomeForSale&);
      }
      

      在成员函数和友元函数中调用,能通过编译,但不能链接,连接器会报错

      • 在编译阶段避免链接期错误,设计一个专门阻止拷贝动作的基类,HomeForSale继承基类
      class Uncopyable {
      protected:
      		Uncopyable() { }
      		~Uncopyable() { }
      private:
      		Uncopyable(const Uncopyable&);
      		Uncopyable& operator=(const Uncopyable&);
      };
      
      class HomeForSale : private Uncopyable {    // 不再声明 拷贝构造函数和赋值运算操作符
      	...
      };
      

      这里使用了private继承,public继承是is a关系,两者使用注意事项详见32和39。

    07: Declare destructors virtual in polymorphic base classes

    为多态基类声明virtual析构函数

    • 多态的基类应该声明一个virtual析构函数;如果类带有任何virtual函数,也应该拥有一个virtual析构函数
    • 类的设计目的不是作为基类使用,也不是为了具备多态性,则不应该声明virtual析构函数
      原因:
      实现虚函数的对象,包含了虚函数表指针(virtual table pointer),vptr指向一个由函数指针构成的数组
      • 对象的体积会增加(32位计算机上为4字节,64位计算机上为8字节)
      • 和其他语言(如C语言)不再具有移植性,除非额外实现
    • 所有的STL容器带有non-virtual析构函数,如vector,list,set等,避免继承一个标准容器或其他带有non-virtual析构函数的类
    • 纯虚函数不能被实例化

    08: Prevent exceptions from leaving destructors

    别让异常逃离析构函数

    • 在析构函数中加入 try catch,吞下异常
    • 提供新的函数关闭连接供客户使用

    09: Nevel call virtual functions during construction or destruction.

    绝不在构造和析构过程中调用virtual函数

    • 构造和析构函数不会调用到子类的虚函数

    10: Have assignment operators return a reference to *this

    令 operator= 返回一个 reference to *this

    • 实现了连续复制的语义:
      x = y = z = 1; ==> x = (y = (z = 1));

    11: Handle assignment to self in operator=.

    在operator= 中处理自我赋值

    • 比较来源对象和目标对象的地址
       Widget& Widget::operator=(const Widget& rhs) {
         if (this == &w) return *this;
         delete pb;
         pb = new Bitmap(*rhs.pb);
         return *this;
       }
      
    • 精心周到的语句顺序
       Widget& Widget::operator=(const Widget& rhs) {
         Widget *pOrig = pb;
         pb = new Bitmap(*rhs.pb);
         delete pOrig;
         return *this;
       }
      
    • copy and swap技术:使用拷贝构造函数生成副本cp,交换this与cp,返回this

    12: Copy all parts of an object.

    复制对象时勿忘其每一个成分

    • 新增数据成员,需要修改拷贝构造函数、赋值运算符
    • 继承子类的拷贝函数确保复制了所有父类成分
    • 拷贝构造函数和赋值运算操作符的共同部分,应该放入统一的函数,而不是尝试互相调用
  • 相关阅读:
    Linux文件管理
    网络层基础
    引导与服务控制实验
    交换机基础
    计算机网络基础
    计算机视觉 牛人主页 Hanson
    CV codes代码分类整理合集(http://www.sigvc.org/bbs/thread7211.html) Hanson
    机器学习中的相似性度量 (附matlab代码) Hanson
    机器学习问题方法总结 Hanson
    支持向量机很全的代码和数据集 Hanson
  • 原文地址:https://www.cnblogs.com/izcat/p/13557231.html
Copyright © 2020-2023  润新知