C++ 构造函数中这个奇怪的冒号成员(“:”)语法是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1711990/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is this weird colon-member (" : ") syntax in the constructor?
提问by nils
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 member variable but I've never seen this syntax before. It looks like a function/constructor call but for an int
? Makes no sense for me. Perhaps someone could enlighten me. And, by the way, are there any other esoteric language features like this, you'll never find in an ordinary C++ book?
这个奇怪: bar(num)
是什么意思?它似乎以某种方式初始化了成员变量,但我以前从未见过这种语法。它看起来像一个函数/构造函数调用,但对于int
? 对我来说毫无意义。也许有人可以启发我。而且,顺便说一下,还有其他像这样的深奥的语言特性,你在普通的 C++ 书中永远找不到吗?
采纳答案by James McNellis
It's a member initialization list. You should find information about it in any good C++ book.
它是一个成员初始化列表。您应该在任何好的 C++ 书籍中找到有关它的信息。
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).
在大多数情况下,您应该初始化成员初始化列表中的所有成员对象(但是,请注意 FAQ 条目末尾列出的例外情况)。
The takeaway point from the FAQ entry is that,
FAQ条目的要点是,
All other things being equal, your code will run faster if you use initialization lists rather than assignment.
在所有其他条件相同的情况下,如果您使用初始化列表而不是赋值,您的代码将运行得更快。
回答by Alok Save
Foo(int num): bar(num)
This construct is called a Member Initializer Listin C++.
此构造在 C++ 中称为成员初始值设定项列表。
Simply said, it initializesyour member bar
to a value num
.
简单地说,它将您的成员初始化bar
为一个 value num
。
What is the difference between Initializing and Assignment inside a constructor?
构造函数内部的初始化和赋值有什么区别?
Member Initialization:
成员初始化:
Foo(int num): bar(num) {};
Member Assignment:
成员分配:
Foo(int num)
{
bar = num;
}
There is a significant difference between Initializing a member using Member initializer list and assigning it an value inside the constructor body.
使用成员初始值设定项列表初始化成员和在构造函数体内为其分配值之间存在显着差异。
When you initializefields via Member initializer list the constructors will be called once and the object will be constructed and initialized in one operation.
当您通过成员初始值设定项列表初始化字段时,构造函数将被调用一次,并且对象将在一次操作中被构造和初始化。
If you use assignmentthen 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.
如您所见,后者有额外的创建和分配开销,这对于用户定义的类来说可能相当可观。
Cost of Member Initialization = Object Construction
Cost of Member Assignment = Object Construction + Assignment
The latter is actually equivalent to:
后者实际上相当于:
Foo(int num) : bar() {bar = num;}
While the former is equivalent to just:
而前者相当于:
Foo(int num): bar(num){}
For an inbuilt (your code example) or POD class members there is no practical overhead.
对于内置(您的代码示例)或 POD 类成员,没有实际开销。
When do you HAVE TO use Member Initializer list?
什么时候必须使用成员初始值设定项列表?
You will have(rather forced) touse a Member Initializer list if:
如果出现以下情况,您将(而不是被迫)使用成员初始值设定项列表:
- Your class has a reference member
- Your class has a non static const member or
- Your class member doesn't have a default constructor or
- For initialization of base class members or
- When constructor's parameter name is same as data member(this is not really a MUST)
- 你的班级有一个参考成员
- 你的班级有一个非静态的 const 成员或
- 您的类成员没有默认构造函数或
- 用于基类成员的初始化或
- 当构造函数的参数名称与数据成员相同时(这不是必须的)
A code example:
一个代码示例:
class MyClass
{
public:
//Reference member, has to be Initialized in Member Initializer List
int &i;
int b;
//Non static const member, must be Initialized in Member Initializer List
const int k;
//Constructor's parameter name b is same as class data member
//Other way is to use this->b to refer to data member
MyClass(int a, int b, int c):i(a),b(b),k(c)
{
//Without Member Initializer
//this->b = b;
}
};
class MyClass2:public MyClass
{
public:
int p;
int q;
MyClass2(int x,int y,int z,int l,int m):MyClass(x,y,z),p(l),q(m)
{
}
};
int main()
{
int x = 10;
int y = 20;
int z = 30;
MyClass obj(x,y,z);
int l = 40;
int m = 50;
MyClass2 obj2(x,y,z,l,m);
return 0;
}
MyClass2
doesn't have a default constructor so it has to be initialized through member initializer list.- Base class
MyClass
does not have a default constructor, So to initialize its member one will need to use Member Initializer List.
MyClass2
没有默认构造函数,因此必须通过成员初始值设定项列表进行初始化。- 基类
MyClass
没有默认构造函数,因此要初始化其成员,需要使用成员初始化器列表。
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 notinitialized 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.
它们没有按照在成员初始值设定项列表中指定的顺序进行初始化。
总之,Member 初始化列表不决定初始化的顺序。
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.
鉴于上述情况,保持成员初始化的成员顺序与它们在类定义中声明的顺序相同始终是一个好习惯。这是因为如果两个顺序不同,编译器不会发出警告,但相对较新的用户可能会将成员 Initializer 列表混淆为初始化顺序并编写一些依赖于此的代码。
回答by Josh
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:
考虑这两个例子:
// Example 1
Foo(Bar b)
{
bar = b;
}
// Example 2
Foo(Bar b)
: bar(b)
{
}
In example 1:
在示例 1 中:
Bar bar; // default constructor
bar = b; // assignment
In example 2:
在示例 2 中:
Bar bar(b) // copy constructor
It's all about efficiency.
这一切都与效率有关。
回答by LeopardSkinPillBoxHat
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 constantsor referencesthey mustbe initialized.
这称为初始化列表。它是一种初始化类成员的方法。使用它而不是简单地将新值分配给构造函数体中的成员有好处,但是如果您的类成员是常量或引用,则必须对其进行初始化。
回答by wkl
This is not obscure, it's the C++ initialization list syntax
这并不晦涩,它是C++ 初始化列表语法
Basically, in your case, x
will be initialized with _x
, y
with _y
, z
with _z
.
基本上,在您的情况下,x
将使用_x
, y
with _y
, z
with进行初始化_z
。
回答by AnT
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).
我只想指出,正如您所说,“看起来像构造函数调用”的语法不一定是构造函数调用。在 C++ 语言中,()
语法只是初始化语法的一种标准形式。对于不同的类型,它有不同的解释。对于具有用户定义的构造函数的类类型,它意味着一件事(它确实是一个构造函数调用),对于没有用户定义的构造函数的类类型,它对于 empty意味着另一件事(所谓的值初始化()
),对于非类类型,它又是另一回事意味着不同的东西(因为非类类型没有构造函数)。
In your case the data member has type int
. int
is not a class type, so it has no constructor. For type int
this syntax means simply "initialize bar
with the value of num
" 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.
在您的情况下,数据成员具有 type int
。int
不是类类型,因此它没有构造函数。对于类型,int
此语法仅意味着“bar
使用”的值进行初始化,仅此num
而已。它是这样直接完成的,不涉及构造函数,因为再一次,int
它不是类类型,因此它不能有任何构造函数。
回答by Mark Ransom
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.
我不知道你怎么会错过这个,它很基本。这是初始化成员变量或基类构造函数的语法。它适用于普通的旧数据类型以及类对象。
回答by nos
This is an initialization list. It'll initialize the members before the constructor body is run. Consider
这是一个初始化列表。它会在构造函数体运行之前初始化成员。考虑
class Foo {
public:
string str;
Foo(string &p)
{
str = p;
};
};
vs
对比
class Foo {
public:
string str;
Foo(string &p): str(p) {};
};
In the first example, str will be initialized by its no-argument constructor
在第一个例子中, str 将被它的无参数构造函数初始化
string();
before the body of the Foo constructor. Inside the foo constructor, the
在 Foo 构造函数的主体之前。在 foo 构造函数中,
string& operator=( const string& s );
will be called on 'str' as you do str = p;
将在 'str' 上调用 str = p;
Wheras in the second example, str will be initialized directly by calling its constructor
而在第二个例子中, str 将通过调用其构造函数直接初始化
string( const string& s );
with 'p' as an argument.
以 'p' 作为参数。
回答by pm100
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
如果成员变量类型不支持空初始化或者它是一个引用(不能被空初始化),那么你别无选择,只能提供一个初始化列表
回答by Aric TenEyck
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.
你是对的,这确实是一种初始化成员变量的方法。除了明确表示这是一个初始化之外,我不确定这有什么好处。在代码中使用“bar=num”可能会更容易被移动、删除或误解。