effective C++ 读书笔记(上)

来源:互联网 发布:p2p网贷源码下载 编辑:程序博客网 时间:2024/05/16 17:46

条款05:了解C++默默编写并调用那些函数

      在类的声明中,没有声明而会由编译器声明的有:一个拷贝构造函数,一个拷贝赋值运算符和一个构造函数。也就是说,如果声明了一个带参的构造函数,那么编译器将不会为你声明一个无参的构造函数,因此在声明类的对象时必须调用含参数的构造函数,否则将会编译出错。如果没有声明这个带参的构造函数,反而不会出现这样的错误,这必须十分注意。拷贝赋值运算符使用时,如果类的成员里有引用变量或者常量,那么由于构造函数已经为类的这些成员初始化了,这些成员不能再被赋值,此时编译器就会拒绝生成拷贝赋值运算符。这个时候就需要自己声明并定义一个拷贝赋值运算符了。

 

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

      作者在书里介绍了一种拒绝使用编译器自动生成的函数的方法,比如拷贝构造函数和拷贝赋值运算符。为了不让一些对象拷贝动作发生且在编译期就阻止它。作者定义了一个基类,派生类以私有形式继承该基类,那么基类的拷贝构造函数将不能被派生类调用,这样在对派生类对象进行拷贝操作时,自动调用基类拷贝函数的动作被认为是非法的,这样派生类的拷贝也无法进行。

 

条款13:以对象管理资源

      有时候需要将资源放进对象内,这样可以借助对象的析构函数来确保资源被释放。这里介绍了智能指针auto_ptr。auto_ptr被当作一般指针使用,但是该指针被销毁时将会自动删除它指向之物。使用它必须十分小心,不能让多个指针指向一个已经由auto_ptr指向的对象。为此,auto_ptr被赋予了一个特殊的性质:若通过拷贝构造函数或拷贝赋值操作符复制它们,它们会变成null,而复制所得的指针将取得资源的唯一拥有权。

 

      这在一些情况下是不能被接受的。因此就有了另一个方案:“引用计数型智慧指针”(RCSP)。所谓RCSP也是一个智能指针,持续追踪共有多少对象指向某笔资源,并在无人指向它时自动删除该资源。TR1的tr1::shared_ptr就是一个RCSP。

 

条款14:在资源管理类中小心复制行为

      这里书的作者提到了一个RAII的概念,它的字面意思是“资源获取即初始化”。

      tr1:shared_ptr允许指定所谓的“删除器”,那是一个函数或函数对象,当引用次数为0时便被调用。删除器对tr1:shared_ptr构造函数而言是可有可无的第二参数,所以代码看起来像这样:

 

 

条款15:在资源管理类中提供对原始资源的访问

      tr1::shared_ptr和auto_ptr都提供一个get成员函数,用来执行显式转换,也就是它会返回只能指针内部的原始指针(的复件)。和(几乎)所有智能指针一样,tr1::shared_ptr和auto_ptr也重载了指针取值操作符,它们允许隐式转换至底部原始指针。

      为了实现自动类型转换,这里介绍了一种方法:

 

 

条款18:让接口容易被正确使用,不易被误用

      explicit关键字。该关键字用在单参数(不包含默认参数)的构造函数前,用以阻止对该类的隐式转换。

 

条款24:若所有参数皆需类型转换,请为此次啊用non-member函数

      Scott(书的作者)提到:如果你需要为某个函数的所有参数(包括被this指针所指的那个隐喻参数)进行类型转换,那么这个函数必须是个non-member。

 

条款25:考虑写出一个不抛异常的swap函数

      先看如下的代码:

 

      一些细节并不重要,重要的部分是这个swap函数针对Widget特化了。“这个函数一开始的“template<>”表示它是std::swap的一个全特化版本,函数名称之后的“<Widget>”表示这一特化版本系针对“T是Widget”而设计。换句话说当一般性的swap template施行于Widget身上便会启用这个版本。通常我们不能够改变std命名空间内的任何东西,但可以为标准template制造特化版本,使它专属于我们自己的classes。”【P107】

 

条款27:尽量少做转型动作

      C++还提供了四种新式转型:

      const_cast<T> (expression)

      dynamic_cast<T> (expression)

      reinterpret_cast<T> (expression)

      static_cast<T> (expression)

      各有不同的目的:

  • const_cast通常被用来将对象的常量性移除。它也是唯一有此能力的C++-style转型操作符。
  • dynamic_cast主要用来执行“安全向下转型”,也就是用来决定某对象是否归属继承体系中的某个类型。它是唯一无法由旧式语法执行的动作,也是唯一可能耗费重大运行成本的转型动作。
  • reinterpret_cast意图执行低级转型,实际动作(结果)可能取决于编译器,这也就表示它不可移植。例如将一个pointer to int转型为一个int。这一类转型在低级代码意外很少见。
  • static_cast用来强迫隐式转换,例如将non-const对象转为const对象,或将int转为double等等。它也可以用来执行上述多种转换的反向转换,例如将void*指针转为typed指针,将pointer-to-base转为pointer-to-derived。但它无法将const转为non-const——这只有const-cast能办到。

      以下的代码是很有趣的:

 

      这段程序将*this转型为Window,对函数onResize的调用也因此调用了Window::onResize。但恐怕你没有想到,它调用的并不是当前对象上的函数,而是稍早转型动作所创建的一个“*this对象之base class成分”的暂时副本身上的onResize!那么如果Window::onResize修改了对象内容,当前对象其实没被改动,改动的是副本。然而SpecialWindow::onResize内如果也修改对象,当前对象会被改动。所以正确的应该是如下代码:

 

 

原创粉丝点击