default constructor(默认构造函数)

来源:互联网 发布:淘宝联盟怎么找免单 编辑:程序博客网 时间:2024/05/16 10:15

default constructor(默认构造函数)

    如果你没有写自己的构造函数,那么编译器会为你写一个。事实上,默认构造函数的使用远非如此。在不使用编译器提供的构造函数之外,有些时候,我们需要默认构造函数,比如构造内置类型int为0,指针为NULL等等,但有时候,我们不能提供默认构造函数,而必须显式指定构造函数参数,以防止无意义的值出现。像一个存储学生信息的类,如果有默认构造函数的话,那么该提供一个什么样的默认值呢,很显然,无论如何这个值可能都是无意义的~因此必须使用有参构造,才能避免程序出现不可预期的行为。

    默认构造函数有什么用呢?以这个测试类为例

    class Widget
    {
          private:
                 int i;
          public:

                                       Widget():i(0){}                //默认构造函数
                 Widget(int ii):i(ii){}          //有参构造函数
                 void print() const { cout<<i<<endl; }
                 ~Widget() { cout<<"destructor called here~"<<endl; }
    };

    首先来说,它允许无参创建一个类对象:

      Widget w;                  //OK,调用默认构造函数

    这一点对于构建一个数组对象尤为重要:

      Widget array[3];         //OK,有默认构造函数可以使用

    但如果没有定义默认构造函数,而只是定义了上述的有参构造函数,那么可以很明确的告诉你,上述两个语句都是无法通过编译的~

    对于没有提供默认构造函数,而只是提供了有参构造函数的类,如何创建数组对象呢?

    方法一:利用临时对象

    可以通过创建临时对象来对数组中的对象进行初始化:

     Widget array[3]={Widget(11),Widget(22),Widget(33)};

    这种比较繁琐的方式却可以有效的解决问题。但对于构建于Heap的数组此方法却是无能为力。

    方法二:利用数组存储指针

    这在数组或者标准容器中都是一种惯用法,在数组中不直接存储对象,而是存储指向对象的指针:

    Widget* array[3];           //OK,即使没有默认构造函数,照样可以通过编译

    for(int i=0;i<3;++i)

          array[i]=new Widget(parameter);      //这里使用有参构造去创建对象

    这里的对象创建于堆上,因此必须遵循C++的一项准则:你自己new出来的对象必须靠你自己去delete,所以如果你要抛弃这些数组对象,你还必须亲自对他们进行delete,否则的话内存泄漏将使程序崩溃。好麻烦~但更深入的来说,你还耗费了相当一部分的空间,既要保存对象,又要保存对象的指针,虽然现今对空间的要求不是很严格,但在某些情况下,节省空间仍是一个很重要的部分(如果程序运行于嵌入式系统)。解决方法当然也还是存在的~

    方法三:placement new

    解决办法就是利用placement new,意思就是可以将对象放入到指定的内存中去,而这块内存完全由我们自己决定:

     void* memory=operator new[](3*sizeof(Widget));   //分配内存,大小为3个Widget

     Widget* pw=static_cast<Widget*>(memory);        //转换,告诉编译器对象大小

     for(int i=0;i<3;++i)

           new(&p[i]) Widget(parameter);     //把对象放入到指定内存

    但缺点仍然是自己new出来的对象要自己负责,如果想要放弃这些对象,恐怕我们必须要自己动手去调用相应的析构函数,然后在释放掉这部分内存:

      for(int i=0;i<3;++i)

          p[i].~Widget();

    很吃惊吧,因为很少情况下我们需要亲自调用析构函数~当然,事情还没有完,紧接着就要释放掉这部分内存:

       delete [] memory;        //而不是pw,因为pw又不是new出来的,所以删除它无意义

   这对于很多的标准程序库中的模板也是一样,在不提供默认构造参数的情况下,很难使得一些template去含有一个Widget类似的对象,因为它们需要默认构造函数。

    所以,对于默认构造函数,在实际情况下并没有那么简单,至于是否提供它,当然也要根据实际情况来确定。这里讨论的关键在于,如何在不提供的情况下,去取得一些我们需要的诸如类似于数组的行为。

原创粉丝点击