1. 在类内部定义的函数默认为inline,内联函数应该在头文件中定义,因为其定义对编译器必须是可见的,以便编译器能够在调用点内联展开该函数的代码。此时,仅有函数原型是不够的。
2.assert
3.异常
4.由于流对象不能复制,因此不能存储在容器中;由于流不能复制,因此形参或返回类型也不能为流类型,必须用指针或引用,对IO对象的读写会改变它的状态,因此引用必须是非const的。
5.如果需要重用文件流读写多个文件,必须在读另一个文件之前调用clear清除该流的状态。
6.前向声明。在声明之后,定义之前,类是一个不完全类型,即已知它是一个类型,但不知道包含哪些成员。不完全类型只能以有限方式使用。不能定义该类型的对象。不完全类型只能用于定义指向该类型的指针和引用,或者用于声明(而不是定义)使用该类型作为形参类型或返回类型的函数。在创建类的对象之前,必须完整地定义该类。必须定义类,而不只是声明类,这样,编译器就会给类的对象预定相应的存储空间。同样地,在使用引用或指针范文类的成员之前,必须定义类。
7.不能从const成员函数返回指向类对象的普通引用。const成员函数只能返回*this作为一个const引用。
8.引用全局变量
int height;
void dummy(int height)
{
::height = 1;
} 函数中设定全局变量height为1而不是参数height为1.
?
9.必须对任何const或引用类型成员以及没有默认构造函数的类类型的任何成员使用初始化式。
10.按照与成员声明一致的次序编写构造函数初始化列表是个好主意。此外,尽可能避免使用成员来初始化其他成员。
11.实际上,如果定义了其他构造函数,则提供一个默认构造函数几乎总是对的。通常在默认构造函数中给成员提供的初始值应该指出该对象时“空”的。
12.友元不是授予友元关系的那个类的成员,所以它们不受其声明出现部分的访问控制影响。通常,将友元声明成组地放在类定义的开始或结尾是个好主意。友元可以是普通的非成员函数,或前面定义的其他类的成员函数,或整个类。
13.static函数没有this指针,不是任何对象的组成部分,不能声明为const,不能声明为虚函数。
14.static数据成员必须在类定义体的外部定义
15.拷贝构造函数可用于初始化顺序容器中的元素,如
?
vector
svec(5);
编译器首先使用string默认构造函数创建一个临时值来初始化svec,然后使用拷贝构造函数将临时值复制到svec的每个元素。
?
16.为了防止复制,类必须显式声明其拷贝构造函数为private。如果想要连友元和成员的复制也禁止,就可以声明一个private拷贝构造函数但不对其定义,这样在链接时导致错误。
17.不允许复制的类对象只能作为引用传递给函数或从函数返回,它们也不能用作容器的元素。
18.容器中的元素总是按照逆序撤销,先撤销下标为size()-1的元素,最后是下标为0的元素。
19.三法则:指的是如果需要析构函数,则也需要赋值操作符和拷贝构造函数。
20。合成析构函数并不删除指针成员所指向的对象。
21.析构函数没有返回值,没有形参。因为不能指定任何形参,所以不能重载析构函数。虽然一个类可以定义多个构造函数,但只能提供一个析构函数,应用于类的所有对象。
22.析构函数与拷贝构造函数或赋值操作符之间的一个重要区别是,即使我们编写了自己的析构函数,合成析构函数仍然运行。如我们编写了一个空的析构函数,则类的各成员还可以被合成析构函数撤销。合成析构函数在自定义析构函数之后执行。
23.大多数C++类采用以下三种方法之一管理指针成员:
(1)指针成员采取常规指针型行为。这样的类具有指针的所有缺陷但无需特殊的复制控制。
(2)类可以实现所谓的“智能指针”行为。指针所指向的对象是共享的,但类能够防止悬垂指针。
(3)类采取值型行为。指针所指向的对象时唯一的,由每个类对象独立管理。
24.不能重载的操作符
:: .* . ?:
25.重载操作符必须具有至少一个类类型或枚举类型的操作数。这条规则强制重载操作符不能重新定义用于内置类型对象的操作符含义。
26.操作符的优先级、结合性或操作数数目不能改变。除了函数调用操作符operator()之外,重载操作符时使用默认实参是非法的。
27.作为类成员的重载函数,形参看起来比操作数少1.作为成员函数的操作符有一个隐含的this形参,限定为第一个操作数。一般将算术和关系操作符定义为非成员函数,而将赋值操作符定义为成员。
28.重载逗号、取地址、逻辑与、逻辑或等操作符通常不是好做法。这些操作符具有有用的含义,如果我们定义了自己的版本,就不能使用这些内置含义。
29.当一个重载操作符含义不明显时,给操作取一个名字更好。对于很少用的操作,使用命名函数通常比用操作符更好。如果不是普通操作,没有必要为简洁而使用操作符。
30.管理容器键类型和顺序容器的类型应定义==和<操作符,理由是许多算法假定这些操作符存在。例如sort算法使用<操作符,find算法使用==操作符。
31.类定义下标操作符时,一般需要定义两个版本:一个为非const成员并返回引用,另一个为const成员并返回const引用。
32.类型转换函数必须是成员函数,不能指定返回类型,并且形参表必须为空。虽然转换函数不能指定返回类型,但是每个转换函数必须显式返回一个指定类型的值。例如,operator int返回一个int值。转换函数一般不应该改变被转换的对象。因此,转换操作符通常应定义为const成员。
33.类类型转换之后不能再跟另一个类类型转换。如果需要多个类类型转换,则代码将出错。
34.派生类只能通过派生类对象访问其基类的protected成员,派生类对其基类类型对象的protected成员没有特殊访问权限。
35.派生类虚函数调用基类版本时,必须显式使用作用域操作符。如果派生类函数忽略了这样做,则函数调用会在运行时确定并且将是一个自身调用,从而导致无穷递归。
36.private继承时可以在派生类的public部分使用using Base::XX的形式,使得基类的私有成员可以被用户访问。
37.使用class保留字定义的派生类默认具有private继承,而用struct保留字定义的类默认具有public继承。
38.友元关系不能继承。基类的友元对派生类的成员没有特殊访问权限。如果基类被授予友元关系,则只有基类具有特殊访问权限,该基类的派生类不能访问授予友元关系的类。
39.如果基类定义了static成员,则整个继承层次中只有一个这样的成员。无论从基类派生出多少个派生类,每个static成员只有一个实例。
40.构造函数只能初始化其直接基类的原因是每个类都定义了自己的接口。派生类构造函数不能初始化基类的成员且不应该对其基类成员赋值。
41.与构造函数不同,派生类析构函数不负责撤销基类对象的成员,编译器总是显式调用派生类对象基类部分的析构函数。每个析构函数只负责清楚自己的成员。
42.即使没有工作要做,继承层次的根类也应该定义一个虚析构函数。
43.在复制控制中,只有析构函数可以定义为虚函数,构造函数不能定义为虚函数。构造函数是在对象完全构造之前运行的,在构造函数运行的时候,对象的动态类型还不完整。将赋值操作符定义为虚函数将在派生