Effective C++ 笔记

    技术2022-05-11  171

    几乎所有的基类都包含虚函数。 如果某个类不包含虚函数,那一般是表示它将不作为一个基类来使用。当一个类不准备作为基类使用时,使析构函数为虚一般是个坏主意。 对于没有声明相应参数为const的函数来说,传递一个const对象是非法的。 当定义自己的赋值运算符时,必须返回赋值运算符左边参数的引用,*this。如果不这样做,就会导致不能连续赋值,或导致调用时的隐式类型转换不能进行,或两种情况同时发生。 为了高效和避免出错,请尽量使用const和inline而不用#define。 因为<<和>>的多态性,因此免除了数据类型的配对烦恼,故尽量用<iostream>而不用<stdio.h>。 因为malloc和free仅是机械地开辟内存空间,而new和delete会调用其构造函数和析构函数,并且程序员能通过对new和delete的重载来进行开辟空间的安全监测。 注意: #define light_speedp 3e8 // m/sec (in a vacuum) 行尾的注释是成为宏的一部分的。 增加一个指针成员意味着几乎都要进行下面的工作:     ·在每个构造函数里对指针进行初始化。对于一些构造函数,如果没有内存要分配给指针的话,指针要被初始化为0(即空指针)。     ·删除现有的内存,通过赋值操作符分配给指针新的内存。     ·在析构函数里删除指针。 编写安全的new和delete......这个还未能理清思路。 只要类里有指针时,就要写自己版本的拷贝构造函数和赋值操作符函数。                            随着类越来越大,越来越复杂,它们的构造函数也越来越大而复杂,那么对象创建的代价也越来越高。养成尽可能使用成员初始化列表的习惯,不但可以满足const和引用成员初始化的要求,还可以大大减少低效地初始化数据成员的机会。 初始化列表中成员列出的顺序和它们在类中声明的顺序相同,原因是防止某些情况下会因为初始化的顺序而出错。 在赋值运算符中要特别注意可能出现别名的情况,其理由基于两点。 其中之一是效率。     如果可以在赋值运算符函数体的首部检测到是给自己赋值,就可以立即返回,从而可以节省大量的工作,否则必须去实现整个赋值操作。 另一个更重要的原因是保证正确性。     一个赋值运算符必须首先释放掉一个对象的资源(去掉旧值),然后根据新值分配新的资源。在自己给自己赋值的情况下,释放旧的资源将是灾难性的,因为在分配新的资源时会需要旧的资源。     任何时候写一个函数,只要别名有可能出现,就必须在写代码 时进行处理,这是为了避免对象的意外破坏和程序的高效性。     声明为explicit的构造函数会不能进行隐式转换。     假设f是想正确声明的函数,c是和它相关的类: ·虚函数必须是成员函数。如果f必须是虚函数,就让它成为c的成员函数。 ·operator>>和operator<<决不能是成员函数。如果f是operator>>或operator<<,让f成为非成员函数。如果f还需要访问c的非公有成员,让f成为c的友元函数。 ·只有非成员函数对最左边的参数进行类型转换。如果f需要对最左边的参数进行类型转换,让f成为非成员函数。如果f还需要访问c的非公有成员,让f成为c的友元函数。 ·其它情况下都声明为成员函数。如果以上情况都不是,让f成为c的成员函数。 尽量使用传引用而不传值,主要是对象创建和撤掉的开销和“切割”问题。但由于传引用也就是传指针,所以如果对象比较小的话,如char或int,传值会更高效。

    最新回复(0)