Effective C++ (05)

来源:互联网 发布:大数据时代 书 编辑:程序博客网 时间:2024/05/16 14:22

条款28:避免返回handles指向对象内部成分

可能悬空,hanndle指向的东西不再存在

但也有例外:operator[]

避免返回handle:指针、引用、迭代器指向对象内部 

条款29:为异常安全努力

异常安全:

         不泄露任何资源:

         不允许败坏数据

代码越短,出错机会越少

异常安全的函数有以下保证:

         基本保证:如果抛出异常,程序内的任何事物仍然保持在有效状态下

         强烈保证:如果函数成功,是完全成功;如果函数失败,程序会回复到调用前的状态

         不抛异常:承诺绝不抛出异常

异常安全代码满足上述三者之一

copy and swap原则:

         为打算修改的对象作出一份副本,在副本上做修改,若修改抛出异常,则原件不变;如果修改成功,将原件和副本做交换 

条款30:了解inline

免除函数调用的成本

对函数的每一个调用都用函数本体代替

inline函数:

         工作在编译器层,编译器负责做参数检查,返回值类型转换,这是预处理器做不了的。

         对于任何函数,编译器都会把函数声明放入符号表,而inline函数,同时将函数体(源码或汇编取决于编译器)放入符号表。当调用时,做必要的检查,然后插入代码,对于类成员函数,还会插入this指针。

inline的使用

          在类中,如果声明和定义写在一起,则是inline函数

在类外如果定义inline函数,必须声明和定义写在一起

例如,inline void Func(); 然后再别处实现,则没有inline的效果

一般将inline函数定义在头文件中,多个文件包含不会出现重定义(内部链接,保存在符号表里)

inline函数的缺点

和宏一样,其不能调试,inline函数没有地址

inline只是对编译器的一种暗示,编译器有最终inline与否的权利

当有循环时,一般不inline;

当函数体超复杂或较大时,一般不inline;

当函数内递归调用时,绝对不inline;

当须取函数指针时,绝对不inline;

可能引起代码膨胀

将inline函数限制在小型、被频繁调用的函数上 

条款31:将文件间的编译依存关系降至最低

将接口从实现中分离

如果使用对象指针或引用能完成任务,就不要使用对象

尽量以class声明替换class定义 

条款32:确定public继承关系是is-a关系

公开继承意味着is-a的关系

public继承:适用于base class身上的每一件事必须完全适用于子类

         鸟会飞,而企鹅不会,因此不能直接继承于bird 

条款33:继承体系下的名称掩盖

当编译器看到某个name(func 或者 data)时,查找各个作用于,看是否存在name,先从local找,再从base class找

Class Base{Private:Int x;Public:Virtual void mf1() = 0;Virtual void mf1(int);Virtual void mf2();Void mf3();Void mf3(double);};
Class Derived : public Base{Public:Virtual void mf1();Void mf3();Void mf4();};

基类中所有的fm1和mf3都被子类掩盖了!

只要重载了一个fm1,base中所有的fm1都被覆盖

Base::mf1()和Base::mf3()不再被继承

Derived d;int x;d.mf1();             OK    调用Derived::mf1d.mf1(x);           Error!基类中的被掩盖d.mf2();             OK    调用Base::mf2d.mf3();             OK调用Base::mf3d.mf3(x);           Error,被掩盖

掩盖时,只管名字,而不论其类型

例如:

int func(){         doublex;         {                   intx; // 这个x会掩盖外围的double x,如果         }}

可以使用using声明使父类的可见

  

Class Base{Private:Int x;Public:Virtual void mf1() = 0;Virtual void mf1(int);Virtual void mf2();Void mf3();Void mf3(double);};
Class Derived : public Base{Public:Using Base::mf1;// 让base中所有名weiUsing Base::mf3;// mf1 mf3的可见Virtual void mf1();Void mf3();Void mf4();};

Derived d;int x;d.mf1();             OK    调用Derived::mf1d.mf1(x);           OK! 调用基类的!d.mf2();             OK    调用Base::mf2d.mf3();             OK  调用Derived::mf3d.mf3(x);           OK  调用Base::mf3

如果继承base并加上重载,而又想使用base内的func,需要using:: 

在public继承体系下,必须继承所有的方法! 

对于private继承:转向函数

Class Base{Private:Int x;Public:Virtual void mf1() = 0;Virtual void mf1(int);};

Class Derived : private Base{Public:Virtual void mf1(){ Base::mf1();} // 这里为何可见???};
Derived d;int x;d.mf1();             OK    调用Derived::mf1,然后转向调用base的函数d.mf1(x);           Error,Base中的被掩盖

可以使用using或转向函数