《Effectirve C++》笔记(条款1~10)

条款1:视C++为一个语言联邦

C是多种范式汇集的语言,包括C的过程、C面向对象、Template泛型(STL模板库)、模板元编程、lambda。(后面自己补充可能由曲解原文意思)

条款2:尽量以const、enum、inline替换#define

单纯变量用const或enum替换define,形势函数的宏用inline函数替换。

class ttt{
    enum{NumTurns=5};
    int scores[NumTurns];
}

用枚举替换更像define,因为枚举和define均不可取地址,而const的变量可以被取地址。

条款3:尽可能使用const

const char *p;指针非常量,数值为常量--我还是喜欢声明时把*和变量放一起,构成一个整体,这样也容易理解,const就是对这个整体修饰的这个整体不可变也就是*p也就是值不可变。char * const p;指针常量,值非常量 对函数指定const:void a() const;此时函数不可调用非const成员(可以读非const数据成员),如某个数据成员需要被const方法操作,可以用mutable修饰:mutable boos bbb;

const char& operator[](std::size_t position)const {
  XXXXX
  return pText[position];
}
char& operator[](std::size_t position){
  return const_cast(stati_cast(*this)[position]);
}

避免代码重复可用const_cast去掉const符号。先将非const调用过程的this转换为const class object调用,实现对const函数调用,并将返回值的const去掉。注意可以用非const函数使用此方式,不要用const函数通过此方式调用非const函数。

条款4:确定对象使用前已先被初始化

内置(class、struct内)对象需要手工初始化。

构造函数最好用初始化列表,而不是在函数体内进行赋值(函数体内赋值前会自动先对成员进行构造,若没有初始化列表构造时的值是随机的,这样等于两次操作),初始化列表次序随意,但初始化顺序以声明顺序为准。 不同文件中的外部对象初始化顺序不一定,若跨文件调用(以extern方式引用全局变量)不保证其已经被初始化。尽量使用内置对象。

条款5:了解C++默认编写并调用哪些函数

这个对么?这里说编译器会自动创建构造、拷贝、析构函数,但《深度探索C++对象模型》中说的是只有必要的时候才会创建出来。文中说如果有自定义的构造函数则不会创建,但探索中说的是也会在自定义构造前面加东西如果必要。。。。我更原因相信深度探索里写得,因为那样更合理,更高效,通过编译期的复杂判断保证了runtime时的高效。

 

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

将拷贝构造、赋值操作符声明为私有可以禁止此行为。可通过建立一个具有私有拷贝和赋值函数的类并继承此类以避免每个类都重复私有化函数的撰写。

条款7:为多态基类声明virtual析构函数

带多态性质的base class应具有虚析构函数,而不是普通析构函数(这样会导致以base class指针释放派生类时不调用派生类的析构函数,派生类空间未释放),也不是纯虚析构函数(析构调用过程是最深层次的base class的析构最先被调用,若为纯虚将无法调用)

继承stl中的也要注意是否有虚析构,若没有不建议继承。

可以用组合,感觉还是多用组合好。接口要保证虚析构+所有其他均为纯虚函数,没有构造函数。

条款8:别让异常逃离析构函数

析构函数不应该抛出异常:对象在函数结束时自动析构,若出现异常会中断后续对象的析构,若未中断后续析构再出现异常会有多个异常同时出现,这些行为都不可控。

析构函数中若有可能出异常的调用,应自己try catch,并在catch中消除异常不继续上传,或直接调用std::abort结束程序。对于可能发生异常的方法最好提供普通接口供用户直接调用处理,并在析构时亦自动调用以减少一部分错误可能。

条款9:绝不在构造和析构过程中调用virtual函数

对于C++:在构造和析构中不要调用虚函数,因为这样的调用不会真正调用到派生类。java C#没事。

编译期间会自动添加代码完成vptr的指向,并完成基类、成员对象的构造代码的添加以及数据成员构造代码,这些都会增加到函数代码之前(初始化列表的初始化值对应添加到相应构造初始值中)。这样来说构造函数中的代码执行时vptr已经正确指定了,只要派生类重写了就已经指向派生类了。

析构是先调用函数本体,然后进行从深层次到当前的内存释放。

也就是说,如果保证这个构造函数是最后的派生类的构造函数时,是可以在构造、析构中调用虚函数的。如果是基类的构造和析构那么真出现了调用绝对不会调用到派生类。

条款10:令operator=返回一个reference to *this

赋值采用的右结合律 x=(y=(z=15)));

赋值操作符要返回一个对当前对象的引用:

MyStr& operator =(const MyStr& str) {
    return *this;
}
 

你可能感兴趣的:(C++)