• 《Effective C++》笔记


    《Effective C++:改善程序与设计的55个具体作法》 by Scott Meyers

    明智选择+精心设计

    软件设计:“令软件做出你希望它做的事情”的步骤和做法,所谓最佳设计,取决于系统希望做什么事。

    解决一个设计问题的方法不止一种,要训练自己思考多种方法。

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

    定义(definition):提供过编译器一些声明所遗漏的细节。

    切记将成员变量声明为 private

    The protected label gives derived classes access to the protected members of their constituent base-class objects, but keeps these elements inaccessible to users of the classes. from <Accelerated C++>

    protected 和 public 成员变量一样缺乏封装性,如果成员变量被改变,都会有不可预知的大量代码受到破坏。

    初始化(initiation):给予对象初值的过程。C++ 规定:对象成员变量的初始化在进入构造函数本体之前,早于赋值。好的初始化方式(效率高)是使用成员初始化列表(member initialization list)。构造函数本体不必有任何动作。

    初始化顺序:base class 早于 derived class,class 的成员变量总是以其声明次序被初始化

    不同编译单元(源文件)内的 non-local static 对象的初始化顺序属于未定义行为

    default 构造函数:构造函数没有参数 or 每个参数都有缺省值。

    explicit 构造函数:禁止编译器执行非预期的类型转换(隐式类型转换)。

    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 操作符(无新对象被定义)
    
    Widget w3 = w2;     // 调用 copy 构造函数!!!
           // 有新对象被定义(如w3),一定有个构造函数被调用,所以不可能为赋值操作
    

    passed-by-value:意味着“调用 copy 构造函数”。

    使用 passed-by-reference-to-const。效率高(避免了对象创建)、避免了对象切割问题。

    const char *p;       // 常量数据    
    char *const p;       // 常量指针
    const char *const p; // 常量指针 & 常量数据
    

    引用与指针

    • 窥视 C++ 编译器源码,你会发现: reference 以指针实现出来
    • reference 不能为 null
    • reference 必须被初始化
    • reference 相较 pointer 效率高,因为使用 reference 之前不需要测试其有效性(使用 pointer 通常得测试它是否为 null)
    • pointer 可被重新赋值,reference 总是指向(代表)它最初获得的对象(“一旦代表了该对象就不能够再改变”)

    mutable:去除成员变量的 const 属性。被 mutable 修饰的成员变量可能总是会被修改,即使在 const 成员函数内。

    delete:禁止默认拷贝构造函数(copy 构造函数)和赋值操作(copy assignment 操作符)。使用 private 限定符,亦可以达到这个目的(“将成员函数声明为 private 而且故意不实现它们”)。如:

    class ios_base {
    private:
        ios_base(const ios_base&);
        ios_base& operator=(const ios_base&);
    	...
    };
    

    如果为空,编译器为你写函数:

    • default 构造函数(在没有声明任何构造函数的情况下)
    • copy 构造函数
    • 析构函数
    • copy assignment 操作符

    因此,如果你的类:

    class Empty { };
    

    最终是等于写下:

    class Empty {
    public:
    	Empty() { ... }                             //default 构造函数
    	Empty(const Empty& rhs) { ... }             //copy 构造函数
    	~Empty() { ... }                            //析构函数
    	
    	Empty& operator=(const Empty& rhs) { ... }  //copy assignment 操作符	
    };
    

      

    局部销毁:当 derived class 对象经由一个 base class 指针被删除,而 derived class 的析构函数是 non-virtual 的,(结果未定义) 通常情况是 derived 部分没被销毁(隐含的就是资源泄漏)。解决:为多态基类声明 virtual 析构函数。正确做法如:

    class cbase {
    public:
    	cbase();
    	virtual ~cbase(); // !!!
    	...
    };
    
    cbase *pc = new Derived();
    ...
    delete pc; // correct

    另:任何 class 只要带有 virtual 函数都几乎确定有一个 virtual 析构函数。

    • 绝不在析构函数中抛出异常。最好任何情况下都不使用异常。
    • 绝不在构造函数和析构函数中调用 virtual 函数。
    • 令赋值(assignment)操作符返回一个 reference to *this && 避免自我赋值,示例:
    Widget& operator=(const Widget& rhs)
    {
    	if (this == &rhs)  // 防止自我赋值
    		return *this;
    	...
    	return *this;
    }
    
    • 为防止资源泄露,用对象管理,在构造函数中获得资源并在析构函数中释放资源。
    • 好的接口可以防止无效的代码通过编译。
    • 如果成员函数是个 non-virtual 函数,意味着它并不打算在 derived class 中有不同行为,所以绝不该在 derived class 中被重新定义。

    类型转换:

    • const_cast<T>(expression):通常被用来将对象的常量性删除(cast away the constness, const->non-const)。
    • dynamic_cast<T>(expression):继承关系的转型,用来执行“安全的向下转型”,执行速度相当慢(从编译器的角度,通过 strcmp 比较、确认不同的类)。
    • reinterpret_cast<T>(expression):低级转型,其转换结果几乎总是与编译平台息息相关,故不具移植性,如 pointer to int 转型为一个 int。
    • static_cast<T>(expression):用来强迫隐式转换,基本上拥有与 C 旧式转型相同的威力与意义,以及相同的限制。

    2020.7.10待续。。。

  • 相关阅读:
    SQL CREATE TABLE 语句
    SQL CREATE DATABASE 语句
    SQL INSERT INTO SELECT 语句
    SQL SELECT INTO 语句
    Why is chkconfig no longer available in Ubuntu?
    drag-html
    js利用offsetWidth和clientWidth来计算滚动条的宽度
    procomm plus
    很多shell命令后面的单横杠和双横杠,原来这个意思
    angular md-toast 颜色
  • 原文地址:https://www.cnblogs.com/rockyching2009/p/13197548.html
Copyright © 2020-2023  润新知