C ++默认构造函数 [英] C++ Default constructor
问题描述
给定以下代码:
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 $ c $如果 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 typeT
means:
- if
T
is a scalar type (3.9), the object is set to the value of 0 (zero) converted toT
; - 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 forT
is called (and the initialization is ill-formed ifT
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 forT
is called (and the initialization is ill-formed ifT
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屋!