C ++默认构造函数 [英] C++ Default constructor

查看:196
本文介绍了C ++默认构造函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给定以下代码:

  class temp 
{
public:
string str;
int num;
};

int main()
{
temp temp1;
temp temp2 = temp();

cout<< temp1.str< endl; // Print
cout<< temp2.​​str< endl; // Print

cout<< temp1.num< endl; // Print a rand num
cout<< temp2.​​num < endl; // Print 0
}

这两者之间有什么不同?— >

  temp temp1; 

  temp temp2 = temp(); 


解决方案

 ; 

这会调用 temp temp1 的实例。

  temp temp2 = temp 

这会调用 temp 一个临时对象,然后调用临时对象作为参数的 temp2 上的编译器生成的复制构造函数(这当然假定编译器不会删除副本;取决于你的编译器的优化设置。)



至于为什么得到不同的初始化值,标准的第8.5节是相关的:






8.5初始化程序[dcl.init]



第5段:

>如果 T 是标量类型(3.9),则将对象设置为值0(零)转换为 T T 是非联合类类型,每个非静态数据成员和每个基类子对象都是零,
  • 如果 T 是联合类型,对象的第一个命名数据成员是零初始化的;
  • $ b
  • 如果 T 是数组类型,每个元素都是零初始化的;

  • if



  • 默认初始化 em> T 类型的对象表示:




    • 如果 T 是非POD类类型(第9节),调用 T 的默认构造函数if T 没有可访问的默认构造函数);

    • 如果 T 类型,每个元素都是默认初始化的;

    • 否则对象是零初始化的。



    要初始化 T 类型的对象意味着:




    • code> T 是一个具有用户声明的构造函数(12.1)的类类型(第9节),然后是 T (如果 T 没有可访问的默认构造函数,则初始化不成功);

    • 如果 T 是没有用户声明的构造函数的非联合类类型,则T的每个非静态数据成员和基类组件都是值初始化的;

    • 如果 T 是数组类型,则每个元素都被初始化;

    • 否则,对象是零初始化的。



    第7段:

    其初始值为空的圆括号的对象,



    第9段:

    如果没有为一个对象指定初始值设定项,并且该对象是(可能是cv限定的)非POD类类型(或其数组),对象将被默认初始化;如果对象是const限定类型,底层类类型应该有一个用户声明的默认构造函数。否则,如果没有为非静态对象指定初始化器,则对象及其子对象(如果有)具有不确定的初始值;



    12特殊成员函数[special]

    $ b如果对象或任何子对象是const限定类型,
    $ b

    第7段:

    当类用于创建类类型(1.8)的对象时,隐式声明的默认构造函数是隐式定义的。隐式定义的默认构造函数执行类的初始化集合,该类将由用户编写的具有空mem初始化列表(12.6.2)和空函数体的类的默认构造函数执行。



    12.6.2初始化基础和成员[class.base.init]



    第4段:

    如果给定的非静态数据成员或基类没有被mem-initializer-id命名(包括没有mem-initializer-list的情况,因为构造函数没有ctor-initializer),那么




    • 如果实体是(可能是cv限定的)类类型(或其数组)或基类的非静态数据成员,并且实体类是非-POD类,实体被默认初始化(8.5)。如果实体是const限定类型的非静态数据成员,则实体类应具有用户声明的默认构造函数。

    • 否则,实体未初始化。如果实体是const限定类型或引用类型,或者包含(直接或间接)const限定类型的成员的(可能是cv限定的)POD类类型(或其数组)






    现在规则已布局好了, apply:

      temp temp1; 

    temp 是非POD类型因为它有一个 std :: string 成员),并且因为没有为 temp1 指定初始化器, (8.5 / 9)。这将调用默认构造函数(8.5 / 5)。 temp 有一个隐式默认构造函数(12/7),默认初始化 std :: string code> int 成员未完全初始化(12.6.2 / 4)。

      temp temp2 = temp(); 

    另一方面,临时 temp 对象被值初始化(8.5 / 7),该值初始化所有数据成员(8.5 / 5),它调用 std :: string 成员中的默认构造函数,零初始化 int 成员(8.5 / 5)。



    当然,请参考标准在5+不同的地方,只是确保你显式初始化一切(例如 int i = 0; 或使用初始化列表)。


    Given the following code:

    class temp
    {
    public:
        string str;
        int num;
    };
    
    int main()
    {
        temp temp1;
        temp temp2 = temp();
    
        cout << temp1.str << endl; //Print ""
        cout << temp2.str << endl; //Print ""
    
        cout << temp1.num << endl; //Print a rand num
        cout << temp2.num << endl; //Print 0
    }
    

    What is the different between these two?—

    temp temp1;
    

    and

    temp temp2 = temp();
    

    解决方案

    temp temp1;
    

    This calls temp's default constructor on the instance called temp1.

    temp temp2 = temp();
    

    This calls temp's default constructor on a temporary object, then calls the compiler-generated copy-constructor on temp2 with the temporary object as the argument (this of course assumes that the compiler doesn't elide copies; it depends on your compiler's optimization settings).

    As for why you get different initialized values, section 8.5 of the standard is relevant:


    8.5 Initializers [dcl.init]

    Paragraph 5:

    To zero-initialize an object of type T means:

    • if T is a scalar type (3.9), the object is set to the value of 0 (zero) converted to T;
    • if T is a non-union class type, each nonstatic data member and each base-class subobject is zero-initialized;
    • if T is a union type, the object’s first named data member is zero-initialized;
    • if T is an array type, each element is zero-initialized;
    • if T is a reference type, no initialization is performed.

    To default-initialize an object of type T means:

    • if T is a non-POD class type (clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
    • if T is an array type, each element is default-initialized;
    • otherwise, the object is zero-initialized.

    To value-initialize an object of type T means:

    • if T is a class type (clause 9) with a user-declared constructor (12.1), then the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
    • if T is a non-union class type without a user-declared constructor, then every non-static data member and base-class component of T is value-initialized;
    • if T is an array type, then each element is value-initialized;
    • otherwise, the object is zero-initialized.

    Paragraph 7:

    An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized.

    Paragraph 9:

    If no initializer is specified for an object, and the object is of (possibly cv-qualified) non-POD class type (or array thereof), the object shall be default-initialized; if the object is of const-qualified type, the underlying class type shall have a user-declared default constructor. Otherwise, if no initializer is specified for a nonstatic object, the object and its subobjects, if any, have an indeterminate initial value; if the object or any of its subobjects are of const-qualified type, the program is ill-formed.

    12 Special Member Functions [special]

    Paragraph 7:

    An implicitly-declared default constructor for a class is implicitly defined when it is used to create an object of its class type (1.8). The implicitly-defined default constructor performs the set of initializations of the class that would be performed by a user-written default constructor for that class with an empty mem-initializer-list (12.6.2) and an empty function body.

    12.6.2 Initializing bases and members [class.base.init]

    Paragraph 4:

    If a given nonstatic data member or base class is not named by a mem-initializer-id (including the case where there is no mem-initializer-list because the constructor has no ctor-initializer), then

    • If the entity is a nonstatic data member of (possibly cv-qualified) class type (or array thereof) or a base class, and the entity class is a non-POD class, the entity is default-initialized (8.5). If the entity is a nonstatic data member of a const-qualified type, the entity class shall have a user-declared default constructor.
    • Otherwise, the entity is not initialized. If the entity is of const-qualified type or reference type, or of a (possibly cv-qualified) POD class type (or array thereof) containing (directly or indirectly) a member of a const-qualified type, the program is ill-formed.

    So now that the rules have been laid out, let's see how they apply:

    temp temp1;
    

    temp is a non-POD type (because it has a std::string member), and since no initializer is specified for temp1, it will be default-initialized (8.5/9). This calls the default constructor (8.5/5). temp has an implicit default constructor (12/7) which default-initializes the std::string member and the int member isn't initialized at all (12.6.2/4).

    temp temp2 = temp();
    

    On the other hand, the temporary temp object is value-initialized (8.5/7), which value-initializes all data members (8.5/5), which calls the default constructor in the std::string member and zero-initializes the int member (8.5/5).

    Of course, if you much rather not have to refer to the standard in 5+ different places, just ensure that you explicitly initialize everything (e.g. int i = 0; or using initializer lists).

    这篇关于C ++默认构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆