EffectiveC++

EffectiveC++ 
1,C++是由C,Object-Oriented C++(构造函数,析构函数,封装,继承,多态,虚函数),Template C++,STL四个次语言组成的联合。C++高效编程守则取决于使用C++哪一部分。
2,尽量用const enum inline替换#define即宁可以编译器替换预处理器
    以常量替换#define的特殊情况:定义常量指针,通常放在头文件中因此有必要将指针声明为cosnt,如const char * const authorname=“Scott”,需写两次const,更好的是const std::string("Scott");
    class的专属常量:为了将常量作用域限制在class内部,加static;在内部只是声明赋初始值,如果不取地址,可以只声明不定义;
    但如果取某个class的专属常量地址或编译器坚持看一个定义式,需在类外单独声明在实现文件中实现。正常编译器需在实现文件中初始化static声明的变量。
3,取一个enum的地址不合法而取一个#define的地址也不合法,如果不想让别人获得一个pointer或引用可用enum约束。
4,对于单纯常量,最好以const对象或enums替换#define,对于形似函数的宏,最好改用inline函数替换#defines
5,尽可能使用const:它允许指定一个语义约束,而编译器会强制实施这项约束。可以砸classes外部修饰global或namespace变量。也可以修饰文件,函数或区块作用域中被声明为static的对象。也可以
用它修饰classes内部的static后non-static成员变量,也可以修饰指针。
声明一个T* const指针,表示是一个常指针不得指向不同的东西,但它指向的东西的值是可以改动的。若希望迭代器所指的东西不可被改动则声明为const T*;需要的是const_iterator;
6,mutable可以改变const的声明,将某些东西声明为const可帮助编译器侦测出错误用法。
7,确定对象使用前已被初始化。c++规定,对象成员变量的初始化动作发生在进入构造函数本体前。即在{}前用,也可以指定无物作为初始化实参。
8,c++有固定的初始化次序,先基类后继承类。而class的成员变量总是以其声明次序被初始化。
9,为内置型对象进行手工初始化,因为C++不保证初始化它们。构造函数最好使用成员初始值列,而不要在函数体内使用赋值操作。初值列列出的成员变量,排列次序应该和声明次序相同。
    为了免除“跨编译单元初始化次序”问题,以local static对象替换non-local static;
10,编译器默认为一个空类声明构造函数,析构函数,复制构造函数,赋值操作符=;
11,copy构造函数和copy assignment操作符只是单纯的将源对象的每一个non-static成员变量拷贝到目标对象。
12,在类中,所有编译器产出的函数都是public;为了防止自动生成的copy构造函数和copy assingment 可将其声明为private;
12,让类继承:private uncopyable 可防止成员函数和friend函数调用copy构造函数和copy assingment;
13,C++明白指出,当继承类对象经由一个基类指针被删除,而该基类带着一个non-virtual析构函数,其结果未定义=实际执行时通常发生的是对象的继承成分未被销毁,而属于基类的成分被销毁,
通常称为局部销毁可能造成资源泄漏,败坏数据结构。只有将基类的析构函数声明为virtual才会销毁整个对象。
14,欲实现virtual函数,对象必须携带某些信息,主要用来在运行期决定那个virtual函数被调用,这份信息通常由虚拟表指针指出,虚拟表指针指向一个函数指针构成的数组称为虚拟表。
15,析构函数的运作方式是,最深层派生的那个class其析构函数最先被调用,然后是每一个基类的析构函数被调用。
16,给一个基类一个virtual析构函数只适用于带多态性质的基类身上。
17,析构函数绝对不要吐出异常,如果要处理异常则需在非析构函数执行异常处理。
18,绝不要在构造函数和析构过程中调用virtual函数:在继承类对象的基类的构造期间,对象的类型是基类而不是继承类,不只virtual函数会被编译器解析至基类,而对象在继承类执行构造函数前
不会成为一个继承类对象。析构函数类似,一旦继承类析构函数开始执行,对象内的继承类成员变量便呈现未定义值。
19,在赋值重载的函数中,返回类型为类的引用,而return *this;
20,复制所有local成员变量,调用所有base classes 内的适当coping函数,防止部分复制。copying函数应该确保复制对象内的所有成员变量及所有base class 成分。
21,为防止资源泄漏,请使用RAII对象,它们在构造函数中获得资源,并在析构函数中释放资源。两个常用的RAIIclasses是shared_ptr和auto_ptr;
22,RAIIclass coping行为是禁止coping,实行引用计数法
23,每个RAIIclass 应该提供一个“取得其所管理之资源”
24,当new动态生成一个对象:1,内存被分配出来,2针对此内存会有一个构造函数被调用。调用new时使用[],在调用delete时使用[];
25,设计class犹如设计type:重载函数和操作符,控制内存的分配和归还,定义对象的初始化和终结。
    新type的对象应该如何别销毁和创建(内存的分配和释放),对象的初始化和赋值有什么样的差别(初始化和赋值的差别),新对象如何以值传递(copy构造函数用来定义一个type的传值)
    什么是新type的合法值(错误检查),新type需要配合继承图系吗?(继承了基类就要受到其的束缚,基类的函数时virtual或non-virtual;若允许其他类继承,会影响自己声明的函数尤其是析构函数是否为virtual)
    新type需要什么样的转换(是否隐式转换或显示,如果只允许explicit则需专门的转换函数),什么样的操作符合函数对此新type是合理的,什么样的标准函数应该驳回(正是必须声明为private)
    谁该取用新type成员(有助于决定public,protected,private),什么是新type的“未声明接口”
26,尽量以const &代替传值:传值的传传递的是复制,需要多次的构造和析构,加const防止传入函数内部被改变。引用不需要调用任何构造和析构函数且防止了只传基类切割了继承类。
27,返回对象时,别妄想返回指针或指向一个本地栈的引用:将成员变量声明为private
28,以non-member,non-friend替换member函数;namespace和classes不同,前者可跨越多个源码文件而后者不能。
29,若所有参数(包含别this指针所指的隐喻参数)皆需要类型转换,请采用non-member函数
30,尽可能延后变量定义式的出现,这样可增加程序的清晰度并改善程序效率。
31,const_cast:通常用来将对象的常量型转移。dynamic_cast主要用来执行向下安全转型即用来决定某对象是否归属继承体系中的某个类型。reinterpret_cast:执行低级转型,列如将一个指向整型的指针转为int
static_cast:强迫隐士转换:将non_const转为const对象或将void*指针转为typed指针,将基类指针转为继承类指针但无法将const转为non-const;
32,带有异常安全的函数会:不泄漏任何资源,不允许数据败坏。
33,inline函数:看起来像函数,动作像函数,比宏好的多,且又不会像函数调用那样招致额外的开销。大多数inline限制在小型,被频繁调用的函数身上。通常置于头文件,是编译期行为。
34,如果对象引用或对象指针可以完成任务就不要用对象;尽量以class声明式替换class定义式。为声明式和定义式提供不同的文件。程序库头文件应该以“完全且仅有声明式”的形式存在
35,public继承意味着is-a即告诉编译器继承类是一个继承对象同时也是一个基类对象,反之不成立。
如果尝试带着其他意义则惹祸上身;virtual函数意味着接口必须被继承。non-virtual函数意味着接口和实现都必须被继承。
36,public继承意味着is-a,适用于基类上的每一个事情也一定适用于继承类,因为每一个继承类对象都是一个基类对象。
37,继承类作用域被嵌套在基类作用域内。继承类的名称会遮掩基类内的名称,为了防止可用using声明式或转交函数(用inline)
38,区分接口继承和实现继承:声明一个函数的目的是为了让继承类只继承函数接口。声明一个非纯虚函数,的目的是基类会提供一份代码实现,同时继承类可以覆写它(继承接口和一份缺省实现)。
    声明non-virtual函数的目的是为了继承类的继承函数的接口及一份强制性的实现(继承接口和一份强制实现)。
31,在成员函数内定义函数就默认为了inline函数。非虚函数在类内都是静态绑定,虚函数是动态绑定。
32,任何情况下都不应该重新定义一个继承而来的non-virtual函数。
33,只能继承vitual和non-virtual函数而重新定义一个继承而来的non-virtual函数永远是错的。virtual函数时动态绑定(后期绑定)而而缺省参数值是静态绑定(前期绑定)。
34,静态类型是基类,动态类型即目前所指对象的类型是子类可以在程序执行过程中改变。
35,绝对不要重新定义一个继承而来的缺省参数值,因为缺省参数值都是静态绑定的。而virtual函数-你唯一应该复写的东西却是动态绑定。
36,通过复合塑模出has-a或根据某物实现出:
37,private继承纯粹只是一种实现技术,它的子类成员都是private的。
38,在templates及泛型编程的世界显示接口和运行期多态重要性降低,反倒是隐士接口和编译期多态移到前头了。
39,以不同的template参数具现化function templates会导致调用不同的函数,这便是所谓的编译期多态。
40,classes和templates都支持接口和多态,对classes接口是显示的以函数标签为中心,多态则是通过virtual函数发生在运行期。对template接口是隐士的奠基于有效表达式。多态通过template具现化和函数
重载解析发生于编译期。
41,如果编译期间有足够信息来决定哪个信息传至哪一家公司则可采用template解法。
42,将与参数无关的代码抽离templates,templates是节省时间和避免代码重复的一个奇妙方法。
43,运用成员函数模板接受所有兼容类型。所谓智能指针是行为像指针并提供指针没有的技能
44,需要类型转换时请为模板定义非成员函数。
45,模板元编程是以c++写成,执行于编译期内的程序。
46,不要忽视编译器的警告。

你可能感兴趣的:(C语言)