分类: C/C++
2006-07-27 17:17:37
看完题目我的第一个感觉,构造函数我知道。构造函数是一个类的成员函数,构造函数和析构函数是进行对象数据的创建,初始化,清除工作的成员函数,可以重载构造函数,使一个类不止具备一个构造函数,因有时需要以这些方法中的某一种分别创建不同的对象。不能重载析构函数。构造函数作为成员函数和类有相同的名字。例:一个类名为:aClass,构造函数就是aClass()。构造函数没有返回值,而且不能定义其返回类型,void也不行。析构函数同样使用这一点。当编写重载函数时,只有参数表不同,通过比较其参数个数或参数类型可以区分两个重载函数。但是我读完第一小段后就知道这一章要告诉我们什么了。
这一章并不是要告诉我们什么是构造函数,它的作用是什么。而是要告诉我们的是构造函数是如何工作的。我的。在得知这点后我很兴奋,因为我确实不知道构造函数是如何构造一个类的对象的,并且一直想知道。我一直对面向对象神奇的功能很感兴趣。为什么一个类在被实例化时,可以自动的完成很多工作,使我们的主函数清晰,简单,稳健,高效。以前只看到了表面,没有深入,这会我们有机会去皮剔肉深入骨髓了。 书上主要讨论了几种情况:
带有缺省构造函数的成员对象。如果一个类没有任何的构造函数,但他有一个成员对象,这个对象的类有一个缺省的构造函数,那么编译器会在需要的时候为这个类合成一个构造函数。
举个例子:
我们有以下几个类。它们都有一个构造函数。
猫{public:猫(),......}; 狗{public:狗(),......}; 鸟{public:鸟(),......}; 鱼{public:鱼(),......}; |
我们又有一个类。宠物,我们将猫作为它的成员之一。并且没有给它声明构造函数。
宠物{ public: 猫 一只猫; 狗 一只狗; 鸟 一只鸟; 鱼 一只鱼; private: int ival; ...... } |
则当需要的时候编译器会为它合成一个构造函数,并且采用内联方式。大概象下面的样子。
inline 宠物::宠物() { 猫.猫::猫(); 狗.狗::狗(); 鸟.鸟::鸟(); 鱼.鱼::鱼(); ival=0; } |
为什么会这样,我们来看看编译器的行动。编译器开始执行用户的代码,准备生成宠物对象之前,会首先调用必要的构造函数,来初始化类的成员,以便为对象分配合适的内存空间。结果编译器会合成上面的构造函数,如果程序员为宠物类写了一个构造函数。 宠物::宠物(){ival=0;}那编译器也会将这个构造函数扩张成上面的那样。编译器是怎样实现的呢?原来当一个类没有任何用户定义的构造函数,而是由编译器自动生成的话,则这个被暗中生成的构造函数将会是一个没有什么用处的构造函数。但是通过编译器的工作能够为我们合成一个nontrivial default constructor.
好象香港电影中演的,如果你惹上官司(你要设计一个类),你又没有钱去请高级的律师(没有给出构造函数),那会给你分配一个律师(缺省的构造函数),当然这个律师的能力也许和那些大律师比起来有差距(trivial)。不过我们要知道他们也不是一点用都没有。但是由于有律师行的督导,可以使这些律师能够努力做到最好(nontrivial)。
同样的道理,我们可以理解另外的几种nontrivial default constructor的情况。
如果你的类没有任何的构造函数,并且它派生于一个有着缺省构造函数的基类,那这个派生类的缺省构造函数会被视为nontrivial,因此需要被合成出来,他的合成步骤是调用上一层基类的缺省构造函数,并根据它们的声明次序为派生类合成一个构造函数。
如果类声明或继承了一个虚函数,或者类派生于一个继承串链,其中有一个或更多的虚拟基类。由于缺少使用者声明的构造函数,则编译器会合成一个缺省的构造函数,以便正确的初始化每一个类对象的vptr。
最后说一点,在合成的缺省构造函数中,只有基类的子对象和类的成员对象会被初始化,所有其他的非静态数据成员都不会被初始化,因为这些操作是需要程序员来做的。编译器没有必要连这些工作都做了。 好了,这篇就写到这里吧。这本书真的是雷神所看过的书中,看的最慢的一本了。但这些深层的知识有必要了解的很清楚吗,我们不知道编译器如何合成缺省的构造函数不也能写程序吗?雷神用侯大师的话来回答这个问题:练从难处练,用从易处用。知其然而不知其所以然,不是一个严谨的学习态度。