4、确定对象被使用前已被初始化
在使用变量时不进行初始化是不好的行为,在程序中有可能读入一个未初始化的值就可能导致程序崩溃。
对于内置类型,保证在使用对象之前进行初始化:
int x = 0;
const char* text = "A C-style string"
double d;
std::cin >> d;
对于结构体成员的初始化,要区别初始化和赋值的区别:
class PhoneNumber
{
private:
int name;
int number;
public:
PhoneNumber(){name = 0;number = 0;} //这里是赋值不是初始化
PhoneNumber():name(0),number(0){} //这里才是初始化(成员初值列)
};
在C++中,对象的成员变量的初始化动作发生在进入构造函数本体之前,上面利用成员初值列的方法初始化的效率较高,同时不浪费default构造函数做的一切
另外一种情况,C++对“定义于不同编译单元内的non-local static对象”的初始化相对次序并无明确定义。也就是如果某编译单元内的某个non-loacl static对象的初始化动作使用了另一个编译单元内某个non-local static对象,而它所用到的这个对象可能尚未被初始化,如果出现这种情况,那么问题是致命的。
解决这个的方法就是将每个non-loacl static对象搬到自己的专属函数内(该对象在此函数内被声明为static)。这些函数返回一个reference指向它所含的对象。然后用户调用这些函数,而不直接指涉这些对象。这个手法的基础在于:C++保证,函数内的local static对象“会在该函数被调用期间”、“首次遇上该对象之定义式”时被初始化:
class FileSystem{...};
FileSystem& tfs() //这个函数用来替换tfs对象;它在FileSystem class
{ //中可能是个static。定义并初始化一个local static对象,
static FileSystem fs; //返回一个reference指向上述对象。
return fs;
}
class Directory{...};
Directory::Directory(params)
{
...
std::size_t disks = tfs().numDisks(); //调用对象
...
}
Directory& temDir() //定义temDir对象为“函数对象”
{
static Directory td;
return td;
}
如此,在调用temDir对象时,C++会对tfs进行初始化,并对temDir也进行初始化
5、了解并拒接默默调用的函数
空类并不是空类,C++编译器会自动为其声明一个copy构造函数、一个copy assignment操作符和一个析构函数,如果你没有声明任何构造函数,那么编译器也会为你声明一个default构造函数(这些函数都是public且inline的)。
这些会引起一些比较容易忽视的问题:比如通过copy assignment操作符去给一个类赋值一个拥有不能进行赋值成员的类时会引起编译器的警告(类中有引用成员,将这个类用过=号赋予给另一个类时会出现错误,因为C++不允许reference改变指向对象)
解决这个“麻烦”的方法,即不想使用编译器自动生成的函数。手动声明copy构造函数和copy assignment操作符,将其为private:
class Uncopyable
{
protected:
Uncopyable(){}
~Uncopyable(){}
private:
Uncopyable(const Uncopyable&);
Uncopyable& operator=(const Uncopyable&);
};
class HomeForSale:private Uncopyable{
...
};
这样,任何想尝试拷贝HomeForSale对象的行为编译器会进行报错。
6、别让异常逃离析构函数
析构函数绝对不要吐出异常。如果一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉异常,然后吞下他们(不传播)或者结束程序;
如果客户需要对某个操作函数运行期间抛出的异常做出反应,那么class应该提供一个普通函数(而非在析构函数中)执行该操作。
22、将成员变量名声明为private
class AccessLevels
{
public:
int getReadOnly() const {return readOnly;}
void setReadWrite(int value) {readWrite = value;}
int getReadWrite() const { return readWrite;}
void setWriteOnly(int value) {writeOnly = value;}
private:
int noAccess; //对此int无任何访问
int readOnly; //对此int做只读访问
int readWrite; //对此int做读写访问
int writeOnly; //对此int做只能写访问
};
写成上述这样是值得建议和安全的,有以下好处:
1、完美的封装性,不管你的成员变量以后怎么变使用者都不会知道;
2、可以为“所有可能的实现”提供弹性。
类中所有的成员变量都应该为private,不管是public还是protected都是不安全的,因为一个可以被所有人访问,另一个可以被所有“亲戚”访问,protected相比较public并不具有多好的隐秘性。