构造函数中的这个怪异的结肠成员(“:”)语法是什么?
最近,我看到了以下示例:
#include <iostream>
class Foo {
public:
int bar;
Foo(int num): bar(num) {};
};
int main(void) {
std::cout << Foo(42).bar << std::endl;
return 0;
}
这个奇怪的:bar(num)
是什么意思?它似乎以某种方式初始化了数据成员,但是我以前从未见过此语法。它看起来像函数/构造函数调用,但对于int
。这对我没有意义。
还有其他像这样的深奥语言功能,您在普通的C ++书中永远不会找到吗?
Recently I've seen an example like the following:
#include <iostream>
class Foo {
public:
int bar;
Foo(int num): bar(num) {};
};
int main(void) {
std::cout << Foo(42).bar << std::endl;
return 0;
}
What does this strange : bar(num)
mean? It somehow seems to initialize the data member, but I've never seen this syntax before. It looks like a function/constructor call but for an int
. This makes no sense to me.
Are there any other esoteric language features like this, you'll never find in an ordinary C++ book?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(14)
该构造在C ++中称为成员初始化器列表。
简而言之,它初始化您的成员
bar
to valuenum
。构造函数内的初始化和分配有什么区别?
成员初始化:
成员分配:
使用成员初始化器列表初始化成员和在构造体主体内部分配值之间存在显着差异。
当您 初始化 通过成员初始化器列表列表将调用一次构造函数,并且将在一个操作中构造和初始化对象。
如果您使用 分配 ,则将首先使用默认构造函数初始化字段,然后用实际值重新分配(通过分配运算符)。
如您所见,还有一个额外的创作开销&amp;后者的作业,对于用户定义的类可能很大。
后者实际上等同于:
虽然前者相当于:
对于内置的(您的代码示例)或POD类成员,但没有实际的开销。
您什么时候必须使用成员初始化列表?
您将有(而不是强制)使用成员初始化器列表,如果
代码示例:
myClass2
没有默认构造函数,因此必须通过成员初始初始化来初始化它列表。myClass
没有默认的构造函数,因此要初始化其成员,需要使用成员初始化器列表。使用成员初始化器列表时要注意的要点:
类成员变量始终以班级声明的顺序初始化。
它们是 note 在它们在成员初始化列表中指定的。
简而言之,成员初始化列表不能确定初始化的顺序。
鉴于以上始终是一个好习惯,即保持成员初始化的成员初始化的顺序与班级定义中声明的顺序相同。这是因为编译器不会警告两个订单是否不同,但是相对较新的用户可能会将成员初始化器列表作为初始化的顺序混淆,并编写一些与此有关的代码。
This construct is called a Member Initializer List in C++.
Simply said, it initializes your member
bar
to a valuenum
.What is the difference between Initializing and Assignment inside a constructor?
Member Initialization:
Member Assignment:
There is a significant difference between Initializing a member using Member initializer list and assigning it an value inside the constructor body.
When you initialize fields via Member initializer list the constructors will be called once and the object will be constructed and initialized in one operation.
If you use assignment then the fields will be first initialized with default constructors and then reassigned (via assignment operator) with actual values.
As you see there is an additional overhead of creation & assignment in the latter, which might be considerable for user defined classes.
The latter is actually equivalent to:
While the former is equivalent to just:
For an inbuilt (your code example) or POD class members there is no practical overhead.
When do you HAVE TO use Member Initializer list?
You will have(rather forced) to use a Member Initializer list if:
A code example:
MyClass2
doesn't have a default constructor so it has to be initialized through member initializer list.MyClass
does not have a default constructor, So to initialize its member one will need to use Member Initializer List.Important points to Note while using Member Initializer Lists:
Class Member variables are always initialized in the order in which they are declared in the class.
They are not initialized in the order in which they are specified in the Member Initializer List.
In short, Member initialization list does not determine the order of initialization.
Given the above it is always a good practice to maintain the same order of members for Member initialization as the order in which they are declared in the class definition. This is because compilers do not warn if the two orders are different but a relatively new user might confuse member Initializer list as the order of initialization and write some code dependent on that.
它是成员初始化列表。您应该在任何好C ++书籍中找到有关它的信息。
在大多数情况下,您应该在成员初始化列表中初始化所有成员对象((但是,请注意,在常见问题解答条目末尾列出的例外)。
常见问题解答条目的要点是,
It's a member initialization list. You should find information about it in any good C++ book.
You should, in most cases, initialize all member objects in the member initialization list (however, do note the exceptions listed at the end of the FAQ entry).
The takeaway point from the FAQ entry is that,
那是构造函数初始化。这是在类构造函数中初始化成员的正确方法,因为它可以防止调用默认的构造函数。
考虑以下两个示例:
在示例1中:
在示例2中:
这全都与效率有关。
That's constructor initialisation. It is the correct way to initialise members in a class constructor, as it prevents the default constructor being invoked.
Consider these two examples:
In example 1:
In example 2:
It's all about efficiency.
这称为初始化列表。这是一种初始化班级成员的方式。使用它是有好处的,而不是简单地为构造函数的主体中的成员分配新值,但是如果您的类成员是 startants 或参考>必须初始化。
This is called an initialization list. It is a way of initializing class members. There are benefits to using this instead of simply assigning new values to the members in the body of the constructor, but if you have class members which are constants or references they must be initialized.
这并不晦涩,是 c ++初始化列表styntax
基本上,在您的情况下,在您的情况下,在您的情况下,
x
将用_x
,y
_y
,z
with代码> _z
。This is not obscure, it's the C++ initialization list syntax
Basically, in your case,
x
will be initialized with_x
,y
with_y
,z
with_z
.另一个已经向您解释说,您观察到的语法称为“构造函数初始化器列表”。该语法使您可以自定义类的基础子对象和类的成员子对象(而不是允许它们默认initialize或保持非初始化)。
我只想注意到,正如您所说,“看起来像构造函数调用”的语法不一定是构造函数调用。在C ++语言中,
()
语法只是初始化语法的一种标准形式。对于不同类型的解释方式有所不同。对于具有用户定义的构造函数的类类型,这意味着一件事(确实是构造函数调用),对于没有用户定义的构造函数的类类型,这意味着另一件事(so so称为 value初始化 )formeet()
)和对于非类型类型,这再次意味着不同的东西(因为非类型没有构造函数)。在您的情况下,数据成员具有类型
int
。int
不是类型,因此它没有构造函数。对于类型int
,本语法简单地表示“初始化bar
具有num
的值”,仅此而已。它是这样的,直接直接涉及构造函数,因为int
再次不是类型的类型,因此它不能具有任何构造函数。The other already explained to you that the syntax that you observe is called "constructor initializer list". This syntax lets you to custom-initialize base subobjects and member subobjects of the class (as opposed to allowing them to default-initialize or to remain uninitialized).
I just want to note that the syntax that, as you said, "looks like a constructor call", is not necessarily a constructor call. In C++ language the
()
syntax is just one standard form of initialization syntax. It is interpreted differently for different types. For class types with user-defined constructor it means one thing (it is indeed a constructor call), for class types without user-defined constructor it means another thing (so called value initialization ) for empty()
) and for non-class types it again means something different (since non-class types have no constructors).In your case the data member has type
int
.int
is not a class type, so it has no constructor. For typeint
this syntax means simply "initializebar
with the value ofnum
" and that's it. It is done just like that, directly, no constructors involved, since, once again,int
is not a class type of therefore it can't have any constructors.我不知道你怎么会错过这个,这是很基本的。这是初始化成员变量或基类构造函数的语法。它适用于普通的旧数据类型以及类对象。
I don't know how you could miss this one, it's pretty basic. That's the syntax for initializing member variables or base class constructors. It works for plain old data types as well as class objects.
这是一个初始化列表。它将在运行构造函数之前初始化成员。
在第一个示例中考虑
VS
将通过其无折磨构造函数初始化STR
,在Foo构造函数的主体之前, 。在foo构造函数内部,
将在“ str” = p时被称为“ str”。
在第二个示例中,str将直接通过
将其构造
函数称为“ P”。
This is an initialization list. It'll initialize the members before the constructor body is run.
Consider
vs
In the first example, str will be initialized by its no-argument constructor
before the body of the Foo constructor. Inside the foo constructor, the
will be called on 'str' as you do str = p;
Wheras in the second example, str will be initialized directly by
calling its constructor
with 'p' as an argument.
您是正确的,这确实是初始化成员变量的一种方式。除了清楚地表明这是一个初始化之外,我不确定这是否有很多好处。在代码中具有“ bar = num”,可以更轻松地移动,删除或误解。
You are correct, this is indeed a way to initialize member variables. I'm not sure that there's much benefit to this, other than clearly expressing that it's an initialization. Having a "bar=num" inside the code could get moved around, deleted, or misinterpreted much more easily.
还有另一个“好处”
如果成员变量类型不支持null初始化或它的参考(不能null初始化),那么您别无选择,只能提供初始化列表,
there is another 'benefit'
if the member variable type does not support null initialization or if its a reference (which cannot be null initialized) then you have no choice but to supply an initialization list
这是构造函数的初始化列表。而不是默认构造
x
,y
和z
,然后分配它们在参数中收到的值,而是将这些成员用这些值初始化放下蝙蝠。对于float
s来说,这似乎并不是很有用,但是它的定制类构造昂贵,这可能是一个延时的时间。It's an initialization list for the constructor. Instead of default constructing
x
,y
andz
and then assigning them the values received in the parameters, those members will be initialized with those values right off the bat. This may not seem terribly useful forfloat
s, but it can be quite a timesaver with custom classes that are expensive to construct.该线程尚未提及:由于C ++ 11,成员初始化器列表可以使用列表限制(又称“统一初始化”,“ Brad Initialition”):
它具有与其他上下文中列表initialization相同的语义。
Not mentioned yet on this thread: since C++11, the member initializer list can use list-initialization (aka. "uniform initialization", "braced initialization"):
which has the same semantics as list-initialization in other contexts.
尽管这是一个古老的讨论,但我找不到有关委托构造师,使用以下方式使用怪异的“:”符号。
它的作用只是简单地将
foo(y)
授予foo('a',y)
。因此,在定义委派构造函数时,除了目标构造函数以外,您在初始化器列表中不能有任何成员。
Although this is an old discussion, I couldn't find any mention about delegating constructor, which uses the weird ":" symbol in the following way.
What it does is simply delegating
Foo(y)
intoFoo('a', y)
. So thatWhen defining a delegating constructor, you cannot have any members in initializer list besides targeted constructor.
类构造函数中的结肠语法(:)是什么?将整数传递到
std :: vector&lt;&gt;
constructor do的是什么?我想从
。表示“初始化列表”的开始,或“ noreferrer”>“ initializer list” ,,,,,将每个变量初始化为括号中的值。好像您正在调用每个变量的构造函数,而该值将传递给该变量的构造函数。
因此,
:root(sz)
用root
变量以int sz
初始化,就像做vector&lt; int&gt; root(sz);
。但是,这样做允许sz
可以传递到unionfind
类构造函数。在此处初始化具有类似大小的向量的构造函数#3( https:// https:/// en.cppreference.com/w/cpp/container/vector/Vector/Vector ):
它构造
count
(SZ
在上面的示例中)向量,每个都带有值t()
,在这种情况下为int() /代码>。
int()
看起来像一个函数调用,但基本上是一个整数默认构造函数值零(0
)。它称为“值初始化” 。如果整数是对象并且具有构造函数,则可以将其视为称为“整数构造函数”。另请参阅我的问题: tochar> char()
是C ++中的函数?因此,让我们回顾一下:
:构造函数中的root(sz)
就像构造vector&lt; int&gt; root(sz);
,它创建sz
root
vector中的元素数,每个元素都具有初始值int(int> int()
,这是零。还要注意,
count
传递给构造函数#3的参数确实应该是size_type
,可以写为std :: vector :: size_type ,通常为
size_t
(请参阅“成员类型”部分在这里)。因此,最好将int sz
更改为size_t sz
。因此,将此构造函数线更改:unionFind(int sz):root(sz){
this:unionfind(size_t sz):root(sz){
。What is the colon syntax (
:
) in the class constructor and what does passing an integer to astd::vector<>
constructor do?I'd like to explain the below example from this duplicate question:
The colon (
:
) signifies the start of an "initialization list", or "initializer list", which initializes each variable to the value in parenthesis. It is as though you were calling a constructor for each variable with that value in parenthesis being passed in to that variable's constructor.So,
: root(sz)
initializes theroot
variable with anint sz
, which is like doingvector<int> root(sz);
. Doing it like this, however, allowssz
to get passed in to theUnionFind
class constructor.Initializing a vector with a size like that is constructor #3 here (https://en.cppreference.com/w/cpp/container/vector/vector):
It constructs
count
(sz
in the example above) number of elements into the vector, each with valueT()
, which meansint()
in this case sinceroot
is avector<int>
.int()
looks like a function call but is basically an integer default constructor to value zero (0
). It is called "value initialization". Think of it like calling an "integer constructor", if integers were objects and had constructors. See also my question here: What is a call tochar()
as a function in C++?So, let's recap:
: root(sz)
in the constructor is like constructingvector<int> root(sz);
, which createssz
number of elements in theroot
vector, each with initial valueint()
, which is the syntax for "value initialization" of anint
to zero.Note also that the
count
parameter passed to constructor #3 shown above really should be asize_type
, which can be written asstd::vector::size_type
, and is usuallysize_t
(see the "Member types" section here). So, it would be better to changeint sz
tosize_t sz
instead. Therefore, change this constructor line:UnionFind(int sz) : root(sz) {
to this instead:UnionFind(size_t sz) : root(sz) {
.