《effective c++》学习笔记
从今天开始看《effective c++》这本书,把学到的东西当做笔记记下来,算是督促自己学习吧,也算是和各人一起分享一点东西,理解不当的地方,请谅解。(每天更新三个条款)。一:让自己习惯C++
条款1:视C++为一个语言联邦
条款2:尽量以const,enum,inline替换#define
条款3:尽可能使用const
条款4:确定对象被使用前已先被初始化
二:构造/析构/赋值运算
条款5:了解C++冷静编写并调用哪些函数
条款6:若不想使用编译器主动生成的函数,就该明确拒绝
条款7:为多态基类声明virtual析构函数
条款8:别让非常逃离析构函数
条款9:绝不在构造和析构过程中调用virtual函数
条款10:令operator=返回一个reference to *this
条款11:在operator=中处理“自我赋值”
条款12:复制对象时勿忘其每一个成分
条款1:视C++为一个语言联邦
主要内容:
1、这个条款主要说把C++看做多个次语言的联邦,包罗C,object-Oriented C++,Template C++,STL。视环境而定用哪一部门。
ps:可能就像我写C++就是套着类的框,写面向过程编程代码~
条款2:尽量以const,enum,inline替换#define
主要内容:
1、宏界说的常量通常在预处理时期就被替换了,所以如果报错的话,可能很难追踪到错误点,用const常量界说会比力好.
2、const替换宏界说有两点必要注意:
(1)界说常量指针的时间,必要指针和指针所指内容都是const,所以用const string比力好。
(2)想要为某个类界说一个专属的常量,这时间用宏界说就不太行了,因为宏界说了之后,整个文件后面都可以用,除非#define #undefine限制?这时间用const常量比力好。
3、假如界说一个const常量作为类的专属常量,这时间类内里有个数组,必要const常量作为其下标,有的编译器可能没办法直接声明const常量的时间界说给于初值,必须在类外去界说初始化。这时间就可以用enum代替const常量。
4、宏也可用来界说函数,它没有函数调用的额外开销,直接是在预处理期间被替换了,但是宏函数也有副作用,这时间用inline去替换宏函数比力好。
条款3:尽可能使用const
主要内容:
1、const可以作用于对象,以及函数各个部门,能用const的地方尽量用const,防止不小心导致的错误更改。
2、const修饰成员函数,成员函数可以进行重载为const和非const成员函数。
调用关系:
(1)const对象可以调用const成员函数,不可以调用非const成员函数,而非const对象可以调用const和非const成员函数。
(2)const成员函数只能调用const成员函数,而非const成员函数可以调用非const成员函数和const成员函数。
3、bitwise constness和logical constness。
(1)bitwise constness以为只要成员函数是const修饰的,那么内里的任何bit都不能修改。不外,假如一个类内里有一个char*类型的指针,我们不能修改指针,但是我们可以修改指针所指物。
(2)logical constness以为成员函数是const修饰的,那么内里的某些bit是可以修改的。比如上述3-1例子,还比如我们有一个类,内里某些成员我们是可以通过mutable进行修饰,达到修改其的意图。
4、const和non-const成员函数避免重复。
成员函数有const和非const,如果内里做的事情一样,会造成代码冗余,解决方法就是通过非const成员函数调用const成员函数,雷同于这样:const_cast<char&>(static_cast<const T&>(*this));也就是说先将对象转为const类型调用const成员函数,因为非const成员函数要返回黑白const的结果,所以用const_cast去除const成员函数返回的结果的const属性。
条款4:确定对象被使用前已先被初始化
主要内容:
1、不管是内置类型还是自界说类型的对象,都应该在使用之前进行初始化,防止出现意想不到的错误(除非你明确其在用之前肯定会被赋值)。
2、尽量使用成员初始化列表去初始化类的成员,一方面是效率会高(省了无畏的赋值),另一个方面是类的某些成员只能通过初始化去完成,比如const类型,引用类型。
3、成员初始化列表初始化成员变量的次序取决于声明成员变量的次序。
4、非局部的static对象(全局的,namespace作用域的或者class内或file作用域内的static对象)在多个文件内里使用时,它在使用之前是否已初始化是不确定的,解决方法是将其搬到自己的专属函数内,然后返回其引用即可,转化为局部的static对象。
5、多线程环境下可能会有竞争,4这个方法不能适用,除非是多线程启动之前,单线程去一一调用函数完成初始化。
条款5:了解C++冷静编写并调用哪些函数
主要内容:
1、一个空的class,编译器默认会生成默认的构造函数,析构函数,拷贝构造,赋值构造函数。生成默认构造和析构函数,作用是调用父类或者非static成员变量的构造和析构函数。如果自己声明确自界说的构造和析构,那么编译器将不会默认生成。拷贝构造,赋值构造函数是浅拷贝,如果类内管理资源,析构的时间可能会有问题,必要重载拷贝构造,赋值构造函数。编译器偶然也会拒绝生成默认的拷贝构造,赋值构造函数,比如类内有const成员或者引用类型成员,如果想要为引用类型成员赋值,就得自己重载拷贝构造,赋值构造函数。
2、父类的拷贝构造函数如果是private的,那么子类也不会生成一个默认的拷贝构造函数,因为没有权限。
条款6:若不想使用编译器主动生成的函数,就该明确拒绝
主要内容:
1、如果不想让类支持拷贝或者赋值,那么可以声明拷贝构造,赋值构造函数两个函数为private,这样做就不会被拷贝或者赋值了,也不用界说出来其实现,防止类内的其他成员函数或者友元函数调用。
条款7:为多态基类声明virtual析构函数
主要内容:
1、类界说出来如果是作为其他类的基类,那么就要给它的析构函数界说为virtual析构函数,防止在开释基类指针指向派生类对象的时间发生内存泄漏。
2、如果类不打算作为其他类的基类,那么就不要把析构函数界说为virtual析构函数,否则对象的体积将会增加,且因含有虚表指针,就不具有移植性了。这是因为实现virtual函数的原理是对象内部包罗了一个虚表指针,基类派生类的虚函数的指针都存放在数组内里,对象调用哪个虚函数,是由虚表指针去函数指针数组内里找到然后调用。每个对象都含有一个虚表指针,一个指针在32位机器上占4个字节,在64位机器上占8个字节。
3、如果类没有将析构函数界说为virtual析构函数,那么最好不要继承它。
条款8:别让非常逃离析构函数
主要内容:
1、析构函数中有非常的话,如果此时是vector类型,那么可能第一个对象就烧毁时就抛非常,继续调用其他对象析构,第二个对象抛出非常,此时系统将会出现不明确的活动或者过早结束,所以不要在析构的时间抛非常。
2、较好的方法是将可能抛出非常的函数开放给用户,让用户去调用,此时用户就会决定非常抛出后的一个反应,程序员在析构时可以加一个双层保险,如果没有调用函数标志,那么析构这里可以调用一次,捕捉非常并且记录或者结束程序。
条款9:绝不在构造和析构过程中调用virtual函数
主要内容:
1、不要在析构或者构造过程中调用virtual函数。假设现在有一个基类A,内里有一个A构造函数,logTransaction虚函数,A构造函数内部调用logTransaction虚函数,此时B和C继承自A类,B和C类重写了自己的logTransaction函数。如果此时界说一个B类,B的构造函数会被调用,但是首先应该先构造B的基类A,这时间A去构造函数过程中调用A类的虚函数logTransaction(基类构造期间,虚函数还不是虚函数),这个征象的原因是此时B类还没有构造好,它内里的成员对象都是未初始化的,编译器会当做B类还不存在。这种代码一样平常编译器会有警告。
2、还有一种环境,当基类构造函数调用普通的init函数,然后init函数内里调用了虚函数,那么此时编译器就有可能就不会有任何告警,但是程序执行征象就不会如我们期望的一样平常。
3、解决方法是基类logTransaction函数不要界说为虚函数,将其界说为普通函数,然后通过构造函数去调用,接受参数,这时间,派生类在构造的时间将自己这边的参数传到基类的构造函数那边,完成调用。也就是说我们无法使用虚函数从基类向下调用,在构造期间,我们可以让派生类将必要的构造信息向上传递给基类构造函数。
条款10:令operator=返回一个reference to *this
主要内容:
1、按照内置类型可以连续赋值的形式,我们在写operator=函数的时间,就必须返回返回*this引用,+=也是如此。否则返回值效率也会降低。
条款11:在operator=中处理“自我赋值”
主要内容:
1、在写operator=的时间,必要处理自我赋值的环境,提高效率,还有一点是必要注意在抛出非常的时间,原本对象已经被破坏的环境,正常来说,应该是先申请临时对象,再进行复制,将原对象开释掉,让指针重新指向新的临时对象,返回*this。
2、如果寻求效率, 可以先把要复制的对象拷贝一份,然后用swap函数互换当前对象和拷贝的临时对象。
条款12:复制对象时勿忘其每一个成分
主要内容:
1、拷贝构造函数和赋值函数中必须处理每一个成员变量,即使是后面新加了一个变量,也要在拷贝构造函数和赋值函数中进行处理。否则会有问题。
2、派生类进行拷贝构造函数和赋值函数的时间,也必要通过派生类的拷贝构造去调用基类的拷贝构造,不能忘记了。
3、不要贪图用拷贝构造函数调用赋值函数,或者赋值函数调用拷贝构造函数。如果真的要消除两者之间重复的代码,可以将重复的代码提取出来为一个init函数,放在private里,让拷贝构造函数和赋值函数调用init函数即可。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]