像下面这样: int x; // x其实也可以认为是一个对象
一个实例就是一个对象 class A{ int a; }; A a;在某些情况下x被初始化为0;a的成员变量也被初始化为0。 但有时候是不确定的,就会有使用了但没被初始化的情况造成无法挽救的影响,有时候会直接使程序崩掉并不知所以,所以好的程序设计应该像下面这样:
int x = 0; // 定义并初始化 class A{ int x = 0, y = 0; // 定义并初始化 }; A a; // 定义即便没有给参数也不会造成不可估计的影响另外: double d; std::cin >> d; // 可以以读取 input stream 的方式完成初始化
不要在类( class )中混淆了初始化和赋值 看看下面的代码:
class Avg{ int _x; int _y; std::string Name; public: Avg(const int& x, const int& y, const std::string& name); }; Avg::Avg(const int& x, const int& y, const std::string& name){ _x = x; //这些都是赋值 _y = y; //而非初始化! Name = name; }构造函数改为下面这样:
Avg::Avg(const int& x, const int& y, const std::string& name) :_x(x), _y(y), Name(name) //现在就是初始化了 {} //构造函数体内不必做任何操作记住: 成员变量是const 或者 reference, 他们就一定需要初值,不能被赋值。 总是使用成员初始化,这样做有时候绝对必要,且有往往比赋值更高效。
class 的成员变量总是以其声明的次序被初始化下面讲讲更深入的 先做名词解释: 所谓 static 对象,其寿命从被构造出来直到程序结束为止。 所谓编译单元是指产出单一目标文件的那些源码。基本上它是单一源码文件加上其所含入的头文件(#include files)。
假如我们至少用到两个以上源码文件,下面列出两:
class FileSystem { //来自我的程序库 public: ... std::size_t numDisks() const; //成员函数 ... }; extern FileSystem tfs; //声明一个外部对象,预备给客户使用; //tfs 代表 "the file system"此时 FileSystem 对象绝不是一个无关痛痒的对象,因为你的客户如果在 tfs 构造完成之前就使用它,会造成严重的后果。
假设某客户创建一个 class 来处理文件系统下的目录(directories)。很自然会用到 FileSystem 创建的对象:
class Directory{ public: Directory(params); ... }; Directory::Directory (params) { ... std::size_t disks = tfs.numDisks(); //使用到 tfs 对象 } //假设进一步,这些客户决定创建一个Directory 对象,用来存放临时文件: Directory tempDir(params); // 为临时文件做的目录看完以上代码,我们大概可以看出初始化次序的重要性了。 但C++ 对“定义于不同的编译单元内的 non-local static ( extern )对象” 的初始化相对次序无明确定义。
但是C++ 保证,函数内的 local static 对象会在“该函数被调用期间” “首次遇上该对象之定义式” 时被初始化。 那么有了以上保证,我们要怎样解决现在这个问题呢,这里介绍一个小小的设计:将每个 non-local static 对象搬到自己的专属函数内(该对象在此函数内被声明为 static)。这些函数返回一个 reference 指向它所含的对象。然后用户调用这些函数,而不是指涉这些对象。换句话说,non-local static 对象被 local static 对象替换了。把上面的代码修改后:
class FileSystem { public: ... std::size_t numDisks() const; //成员函数 ... }; FileSystem& tfs(){ //这个函数用来替代 tfs 对象 static FileSystem fs; //定义并初始化一个 local static 对象 return fs; //返回一个 reference 指向上述对象 } class Directory{ public: Directory(params); ... }; Directory::Directory (params) { ... std::size_t disks = tfs().numDisks(); //改为调用tfs()函数 } Directory& tempDir() //这个函数用来替代 tempDir 对象 { static Directory td; //定义并初始化一个 local static 对象 return td; //返回一个 reference 指向上述对象 }修改后这个系统程序的客户完全可以像以前那样使用它,唯一不同的是现在使用 tfs() 和 tempDir()。也就是说他们使用函数返回的 “指向 static 对象” 的reference,而不再使用 static 对象本身。
最后请记住:
为内置型对象进行手工初始化,因为C++不保证初始化它们。构造函数最好使用成员初值列,而不要在构造函数本体内使用赋值操作。初值列列出的成员变量,其排列顺序应该和它们在类中的声明次序一致。为免除“ 跨编译单元之初始化次序 ”问题,请以 local static 对象替换 non-local static 对象。