条款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::mf1
d.mf1(x); Error!基类中的被掩盖
d.mf2(); OK 调用Base::mf2
d.mf3(); OK调用Base::mf3
d.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中所有名wei
Using Base::mf3;// mf1 mf3的可见
Virtual void mf1();
Void mf3();
Void mf4();
};
Derived d;
int x;
d.mf1(); OK 调用Derived::mf1
d.mf1(x); OK! 调用基类的!
d.mf2(); OK 调用Base::mf2
d.mf3(); OK 调用Derived::mf3
d.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或转向函数