C++ 默认构造函数

来源:互联网 发布:域名代理商 编辑:程序博客网 时间:2024/06/16 10:58

学习《C++ primer》一书,第二次看到构造函数,默认构造函数,合成的默认构造函数时感觉还是不太明白,通过研读书本和查阅高手博文,整理这篇博客,理清思路。正如书中所说构造函数时一个非常复杂的问题,这里只是整理一些肤浅的知识。

定义

  • 构造函数(constructor):
    每个类都分别定义了它的对象初始化的方式,了哦通过一个或几个特殊的成员函数来控制其对象的初始化过程,这些函数就叫默认构造函数。

  • 默认构造函数(default constructor):
    类通过一个特殊的构造函数来控制默认初始化过程,这个函数叫做默认构造函数。
    默认构造函数是可以不用实参进行调用的构造函数,它包括了以下两种情况:
    第一,没有带明显形参的构造函数。第二,提供了默认实参的构造函数。默认构造函数使用可以使用“=default”修饰。

  • 合成默认构造函数(systhesized default constructor):
    编译器创建的构造函数又称为合成的默认构造函数。

注意区别两点,默认初始化和编译器创建的。
类设计者可以自己写一个默认构造函数。编译器帮我们写的默认构造函数,称为“合成的默认构造函数”。

合成默认构造函数初始化规则

  1. 如果存在类内初始值,用它来初始化成员
  2. 否则,默认初始化该成员

编译器何时合成默认构造函数

当用户没有为类定义构造函数的时候,编译器并不是为每个类合都成默认的构造函数,只是在编译器需要的时候才合成默认构造函数。编译器合成默认的构造函数只是满足编译器的编译的需要,而不是满足程序员的需要(例如,成员变量的初始化工作还需要程序员来定义构造函数)。

  • 对象中包含带有默认构造函数的对象,并且该成员的类含有默认构造函数那么C++编译器会帮你给这个类也生成一个默认构造函数,用来调用其成员对象的构造函数,完成该成员的初始化构造。需要强调的是,如果这个成员的类也没有给出默认构造函数,那么C++编译器也不会帮你生成该类的默认构造函数。

  • 这个类的基类有默认构造函数。那么C++编译器也会帮你生成该派生类的默认构造函数,以调用基类的默认构造函数,完成基类的初始化。另外还得强调一下的是,如果基类没有提供这个默认构造的函数,那么C++编译器也不会为派生类生成默认的构造函数(这里包括两层意思,第一,基类没有任何形式构造函数;第二,基类存在其他形式的非默认构造函数,当然了,这种类型就是编译不过的,道理很明显)。

  • 类中存在虚函数。那么C++编译器会为你生成默认构造函数,以初始化虚表(虚函数表vftable)。
    类带有虚函数可以分为两种情况:第一。类本身定义了自己的虚函数。第二,类从继承体系中继承了虚函数(成员函数一旦被声明为虚函数,继承不会改变虚函数的”虚性质“)。这两种情况都使一个类成为带有虚函数的类。

  • 虚继承的类。那么C++编译器会为你生成默认构造函数,以初始化虚基类表(vbtable)。

  • 注意理解“编译器需要的时候”。

    当类只含有内置类型或复合类型的成员时,编译器是不会为类合成默认构造函数的,这种类并不符合”被需要“的条件,甚至当类满足“被需要”条件,编译器合成了默认构造函数时,类中内置类型与复合类型数据成员依然不会在默认构造函数中进行初始化。Primer中也有提到:“如果类包含内置或复合类型的成员,则该类不应该依赖于合成的默认构造函数“。

  • 合成默认构造函数总是不会初始化类的内置类型及复合类型的数据成员。

  • 分清楚默认构造函数被程序需要与被编译器需要,只有被编译器需要的默认构造函数,编译器才会合成它。

某些类不依赖于合成的默认构造函数

合成的默认构造函数只适合非常简单的类,对于一个普通的类来说,必须定义它自己的默认构造函数(区分默认构造函数和合成的默认构造函数),原因有三:
第一,编译器只有在类不包含任何构造函数(注意区分构造函数和默认构造函数)的情况下才会替我们生成一个默认的构造函数,一旦我们定义了一些其他的构造函数,那么除非我们在定义一个默认的构造函数,否则类将没有默认构造函数。我觉得,继承基类的构造函数也应该是构造函数。
第二,对于某些类,合成的默认构造函数可能执行错误的操作。含有了、内置类型或符合类型成员的类应该在类的内部初始化这些成员,或者定义一个自己的默认构造函数。否则,用户在创建类的对象的时候坑你得到未定义的值。原因是,合成的默认构造函数在没有类内初始值的时候执行默认初始化,而内置类型和复合类型默认初始化的值是未定义的。
第三,编译器不能为某些类合成默认的构造函数。例如,如果类中包含一个其他类类型的成员且这个成员的类型没有默认的构造函数,那么编译器将无法初始化该成员。

定义一个自己的默认构造函数

下面是《C++ primer》一书P237页的一个例子。

struct Sales_data{    //构造函数    Sales_data()=default;    Sales_data(const std::string &s):bookNo(s){};    Sales_data(const std::string &s,unsigned n, double p):        bookNo(s),unit_sold(n),revenue(p*n){}    Sales_data(std::istream &);    //其他成员    ...}

从默认构造函数的含义开始:
SaleIdata()=default;
首先明确,因为该构造函数不接受任何实参,所以他是一个默认构造函数。我们定义这个默认构造函数的目的仅仅是因为我们需要其他形式的构造函数,也需要默认的构造函数。我们希望这个函数的作用完全等同于之前我们使用的默认构造函数。
在C++11新标准中,如果我们需要默认的行为,那么可以通过在参数列表后面写上=default**来要求编译器生构造函数**,其中,=default,既可以和声明一起出现在内的内部,也可以作为定义出现在类的外部。

关于=default修饰函数会在后面继续写,地址后续附上。

参考阅读

http://www.cnblogs.com/QG-whz/p/4676481.html
http://www.xuebuyuan.com/1750913.html

读到这了,请点个赞吧

0 0
原创粉丝点击