1.explicit关键字:防止隐式类型转换。该关键字只对含有一个参数的构造函数有效,大于一个参数时,是不会产生隐式转换的。
2.static关键字:向外界隐藏本文件中的函数或者变量、将局部变量保存在静态存储区保证局部变量的全局生存期、默认static变量的初始值为0、类内成员为static时实现同类对象间的数据共享。
【注意】(a)类内static成员变量如果是const型的那么可以在头文件中声明并且定义(初始化)。否则,若类内成员变量是static但非const时,只能在头文件中声明,此时在头文件中初始化是非法的。
(b)类内静态成员函数只能访问类的静态数据和静态成员函数、不能将静态成员函数定义为虚函数、静态成员初始化在类外进行,格式为 <数据类型><类名>::<静态数据成员名>=<值>。
3.const关键字:如果const出现在* 号左边,代表被指物为常量,如果出现在*号右边则表示指针自身是常量。const:*左定左,*右定右。
4.构造函数使内部成员变量初始化或者赋值是不同的概念,其中可以使用[列表初始化],而普通的构造函数是赋值。普通的构造函数首先调用default构造函数为成员变量赋初值,然后对它们在自定义的普通构造函数中赋值,这样一来,default构造函数所做的一切都被浪费了。一条准则就是:列表初始化总要更好,并且总是要在初始值列表中列出所有成员变量,即便没有实际的值。
5.位于不同编译单元内的非函数内部的static对象初始化的时候相对次序并没有明确的定义,如果B单元的使用会调用到A单元内的static成员,这就要求A单元的成员必须先初始化。解决办法是将这些非函数内部的static对象移动到自己的专属函数内,这样B单元只要调用A单元内的专属函数就能保证A单元内期望的static函数能先被初始化。
6.编译器可以暗自为类创建default构造函数、copy构造函数、copy assignment操作符、以及析构函数。对于copy函数及copy构造符,如果两个定义好的类都包含const成员变量或者引用时,默认的构造函数会报错,总之,默认的copy以及copy构造符对类的成员有要求。如果想明确拒绝使用此类默认构造函数,可以将它们声明在private中而不定义,这样外界无法调用这些构造函数并且内部或者友元函数即便能看到也无法执行没有定义的函数。此外介意设计一个基类专门在private中声明这些默认构造函数,这样子类使用private的方式继承基类时,仍可以保留这些默认构造函数失效的特性。
7.当函数的声明中是返回某个基类的对象指针*A,但是返回的对象是其派生类对象指针*B时,可能会存在如下问题:当要删除该函数的对象指针A时(delete A),调用的是基类的析构函数,但实际上应该调用派生类对象的析构函数(delete B),这样就会造成一个诡异的“局部销毁”对象。这就是析构函数定义为virtual的存在必要性。因此,派生一些标准库容器或者是任何不带virtual析构函数的类都是有危险性的。
8.析构函数不要吐出异常,应该在内部消化掉这些异常;如果客户非要在某个函数期间对异常做出反应,那么应该提供一个异常反应函数,而并非在析构函数中执行对异常的反应。
9.如果类的构造或者析构函数要执行一个虚函数,那么会导致这样的后果:派生类在构造或者析构时,只会调用基类的虚函数,也就是说,原本想在派生类的构造函数中执行某些虚函数的操作但是实际上调用的是基类对应的虚函数。原因是:派生类在构造或者析构期间会降级到基类类型,此时虚函数就会被解析成基类对应的函数。解决办法是在类中写一个初始化函数init,这样调用init中的函数就会使用本类中定义的virtual函数。
10.连锁赋值时,采用右结合律。为了实现这样的连锁赋值,操作符“=”应当要返回一个*this.
11.copy函数自定义时,即便自定义函数的拷贝不完全,编译器也不会报错。如果要对派生类实现copying操作,那么从基类继承过来的成员变量并不会被复制,类似于“没看见”。所以copy函数不仅要复制对象内的所有成员变量,还要复制所有从基类继承而来的成分。