在用户自定义构造函数或是拷贝构造函数以后,类中便不会存在默认的无参构造函数和拷贝函数
为什么要有构造函数和析构函数
在我们过去学习C语言编程的时候,我们通常生成的变量都是放在栈区里(auto存储类型)。然而,真正处理实际问题的程序却常常将变量或数组生成在堆区里。
假设我们定义了一个对象obj,此对象有一个占存储很大的成员member,将来要放很大的一篇文章,则我们不希望这个字符数组出现在栈区,而是希望它出现在堆区,如下图所示,
为了实现我们的愿望,我们不能把成员member定义成数组,而是把它定义成指针数据成员,让它指向堆区里的一个占存储很大的字符数组。这样,虽然这个字符数组不是对象的成员,但是,我们能通过指针member访问到它,与这个字符数组是成员的效果是一样的。
据上图(图3‑1)我们看到,有两个东西需要初始化,一个是指针成员member,另一个是堆里的这个数组。这两个东西只能用一条语句生成并初始化,然而这是有问题的。
在C语言里是用等号来表示初始化的,现在我们试着用两个等号来初始化这两个东西:
char* member=new char[10000]= {“large-size string”};
上面的语句中第二个等号语法上是有问题的,本来等号的左边只能是变量名或数组名,但是这个等号的左边却是一个表达式。
C++提供了这样一种解决途径。它提供了一种成员函数,在初始化对象的时候,会自动地调用它。我们称这样的函数为构造函数。在这样的函数里,我们写几个赋值语句:
number=new char[9000];
strcpy(number, “large-size string”);
上述问题就解决了。
现在还有一个问题。当上图(图3‑1)对象obj的生命结束时,obj就要从栈区被释放,然而,指针成员member所指向的堆里的东西不会自动地因此而被释放,这是不符合我们的愿望的。C++提供了这样一种成员函数,在对象被释放的时候,会自动地调用它,我们称这个函数为析构函数。我们只要把delete写到这个函数里,上述问题就解决了。
有教科书在讲述为什么会出现构造函数时说:“比起普通变量,类对象毕竟太复杂了”。笔者不敢苟同。笔者认为,产生构造函数的原因就是为了利于使用堆内存,为了使得初始化语句能够一箭双雕。至于类对象也并非复杂