【Item01】视C++为一个语言联邦 C++体系包括C、Object-Oriented(面向对象编程)、Template(模板)、STL(标准模板库)
【Item02】尽量使用Enum、const、inline代替#define a.#define:在预编译阶段采用直接替代方式,不方便调试 b.const:修饰变量、函数、指针、引用、对象 c.inline:对于短小且调用频繁的函数可以声明为内联函数,提高效率【Item03】切莫使用未初始化的变量或者对象 a.为内置类型进行手动初始化,C++不保证初始化他们 b.构造函数最好(或者一定)使用初始化列表进行初始化,而不是赋值进行初始化(提高效率) c.成员变量初始化顺序为声明顺序,与初始化列表顺序无关【Item05】了解C++默默产生哪些函数 a.当用户未声明构造函数、赋值、复制构造函数,在需要的情况下(也就是说并不一定会生成,只是在需要建立类对象) b.编译器会为类生成默认的构造函数、复制函数、赋值函数 c.一旦用户声明上述函数,则编译器不再自动生成。 d.编译器自动生成的赋值、复制构造函数属于浅复制,当存在指针、引用成员变量时,会导致严重问题。【Item06】若不需要编译器自动生成上述函数,应明确拒绝 a.方式-:用户自己声明赋值、复制构造函数,且权限设为private b.方式二:定义Class UnCopy{ private: UnCopy operator=(UnCopy &rhs); }【Item07】为多态基类定义Virtual析构函数 a.当采用多态形式 Base *pBase = new Derived();
b.若基类析构函数为virtual: delete pBase;//会调用子类的析构函数,不会产生内存泄漏
若基类析构函数为non-virtual:delete pBase;//不会调用子类的析构函数,只能删除子类中基类成员部分,会产生内存泄漏【Item08】别让异常逃离析构函数 a. try...catch捕获 【Item09】不要在构造函数中调用Virtual函数,会导致不可预期的错误 a.在子类构造函数未完成之前,其类型是不完整类型,因此在构造函数中调用virtual函数只会调用基类中virtual函数【Item10】令operator=返回引用,链式编程【Item11】在operator=中处理“自我复制” class ClassName{
public:
//构造函数
.....
private:
char* str;
} 方式一:ClassName& operator=(ClassName& const T){
if(*this==T){
return *this;
}else{
delete str;
str = T.str;
return *this;
//复制操作
}
}
方式二:方式一:ClassName& operator=(ClassName& const T){
//保存旧值
char *oldStr = T.str;
delete str;
str = oldStr;
return *this;
}【Item12】复制对象时,切莫忘记复制基类成员变量(复制函数中调用基类的复制函数)【Item13】以对象管理资源(在对象析构函数中释放资源),避免资源泄漏 例如:智能指针
auto_ptr<ClassName> pInt(new ClassName()); auto_ptr:底层实现调用delete ptr,不能应用于数组,不能复制 shared_ptr:底层实现引用计数,支持复制,资源可以共享【Item14】在资源管理类中小心copying行为 如上auto_ptr、shared_ptr行为
浅复制和深复制的区别,内部含有指针时,只是简单复制指针,造成两个对象耦合,
内部指针指向同一个对象,当一个对象消亡,调用析构函数释放内部指针指向的对象时,
另一个对象的内部指针成为野指针,造成不可预期的错误【Item15】在资源管理类中提供对原始资源的访问方式 即是在资源管理类中提供接口,返回内部原始资源的指针或者引用【Item16】成对使用new和delete。 注意delete和delete[]区别【Item17】以独立语句将new资源指针放入资源管理类(智能指针),防止产生异常 auto_ptr<ClassName> pInt(new ClassName());//有问题,当new ClassName()产生异常时,传入参数是null指针
ClassName *pClassName = new ClassName();
auto_ptr<ClassName> pInt(pClassName);//合理做法【Item18】让接口能够被正确使用,不能被误用。 做好异常值判断,即用户传入任何值都能获得应得的行为【Item19】设计Class犹如设计Type 考虑到各种异常输入【Item20】用pass-by-reference取代pass-by-value 对于一个类对象:传值意味着一次复制构造+一次析构函数的时间成本 对于内置类型pass-by-value更合理【Item21】必须返回对象时,别妄想返回reference 局部对象在函数返回时消亡,返回引用则是无效引用
ClassName& function()
{
ClassName tt;
//do something;
return tt;
}//错误【Item22】将成员变量设为private,提供统一接口,增强封装性 定义setter和getter函数
越少的“人”看到内部成员,则改动时影响越小【Item23】宁以非成员、非友元函数取代成员函数【Item24】若所有参数皆需类型转换,则采用非成员函数 解决classValue*2和2*classValue问题【Item25】考虑写出一个不抛出异常的Swap函数【Item26】尽可能延后对象定义的时间(使用时再定义)【Item27】尽量少做转型操作 const_cast:去除变量const属性 static_cast:隐式转型 dynamic_cast:向下转型 reinterpret_cast:任意转型,破坏性最大【Item28】避免返回Handle指向对象内部成分【Item29】为异常安全而努力是值得的【Item30】透彻了解inline里里外外 将大多数inline限制在小型被频繁调用的函数身上,这可使日后的调试更容易,也可使代码膨胀问题最小化,使程序的速度提升机会更大化
不要只因为function template出现在头文件中,就将他们声明为inline【Item31】将文件间的依存关系降到最低【Item32】确定你的public继承塑造出is-a关系【Item33】避免遮掩继承而来的名称 derived class内的名称会遮掩base class内的名称,在public继承下从来没有人希望如此
为了让被遮掩的名称重见天日,可用using声明式或转交函数【Item34】区分接口继承和实现继承 声明一个纯虚函数目的是让子类只继承函数接口
声明非纯虚函数目的是让子类继承该函数的接口和缺省实现【Item35】考虑virtual函数以外的其他选择【Item36】绝不重新定义继承而来的non-virtual函数【Item37】绝不重新定义继承而来的缺省参数值【Item38】通过组合构造出has-a关系【Item39】明智而审慎使用private继承【Item40】明智而审慎的使用多重继承 多重继承带来对象布局不同,比单一继承复杂,他可能导致新的歧义性,以及对virtual继承的需要
virtual继承会增加大小、速度、初始化复杂度等等成本,如果virtual base class不带任何数据将是最具实用价值的情况【Item41】了解隐式接口和编译器多态
classes和templates都支持接口和多态
class而言接口是显式的,以函数签名为中心,多态则是通过virtual函数发生于运行期
template参数而言,接口是隐式的,奠基于有效表达式,多态则是通过template具现化和函数重载解析发生于编译器【Item42】了解typename的双重意义
template<class T>和template<typename T>意义相同
请使用关键字typename表示嵌套丛书类型名称;但不得在base classlist内 以它作为base class修饰符【Item43】学习处理模板化基类内的名称【Item44】将于参数无关的代码抽离template【Item45】运用成员函数模板接受所有兼容类型【Item46】需要类型转换时请为模板定义非成员函数【Item47】请使用traits class表现类型信息【Item48】认识template元编程【Item49】了解new-handler的行为【Item50】了解new和delete的合理替换时机【Item51】编写new和delete时需要固守常规
0 0