nil*_*ils 325 c++ syntax constructor c++-faq ctor-initializer
最近我见过如下例子:
#include <iostream>
class Foo {
public:
int bar;
Foo(int num): bar(num) {};
};
int main(void) {
std::cout << Foo(42).bar << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这奇怪: bar(num)意味着什么?它似乎初始化成员变量,但我以前从未见过这种语法.它看起来像一个函数/构造函数调用,但对于一个int?对我没有任何意义.也许有人可以启发我.而且,顺便说一下,还有其他类似的深奥语言功能,你永远不会在一本普通的C++书中找到它吗?
Alo*_*ave 307
Foo(int num): bar(num)
Run Code Online (Sandbox Code Playgroud)
此构造在C++中称为成员初始化列表.
简单地说,它会将您的成员初始化bar为一个值num.
会员初始化:
Foo(int num): bar(num) {};
Run Code Online (Sandbox Code Playgroud)
会员作业:
Foo(int num)
{
bar = num;
}
Run Code Online (Sandbox Code Playgroud)
使用成员初始值设定项列表初始化成员并在构造函数体内为其分配值之间存在显着差异.
当你初始化通过成员初始化列表域构造将被调用一次与对象将构造并在一次操作中被初始化.
如果使用赋值,则首先使用默认构造函数初始化字段,然后使用实际值重新分配(通过赋值运算符).
如您所见,在后者中存在创建和分配的额外开销,这对于用户定义的类可能是相当大的.
Cost of Member Initialization = Object Construction
Cost of Member Assignment = Object Construction + Assignment
Run Code Online (Sandbox Code Playgroud)
后者实际上相当于:
Foo(int num) : bar() {bar = num;}
Run Code Online (Sandbox Code Playgroud)
而前者相当于:
Foo(int num): bar(num){}
Run Code Online (Sandbox Code Playgroud)
对于内置(您的代码示例)或POD类成员,没有实际开销.
如果出现以下情况,您将(非常强制)使用"成员初始化程序"列表:
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;
}
Run Code Online (Sandbox Code Playgroud)
MyClass2 没有默认构造函数,因此必须通过成员初始化列表初始化它.MyClass没有默认构造函数,因此要初始化其成员,需要使用Member Initializer List.类成员变量总是按照它们在类中声明的顺序进行初始化.
它们未按成员初始化列表中指定的顺序进行初始化.
简而言之,成员初始化列表不确定初始化的顺序.
鉴于上述情况,保持成员初始化的成员顺序与在类定义中声明它们的顺序始终是一个好习惯.这是因为如果两个订单不同,编译器不会发出警告,但是相对较新的用户可能会将成员初始化程序列表混淆为初始化顺序,并编写一些依赖于此的代码.
Jam*_*lis 205
这是一个成员初始化列表.您应该在任何优秀的C++书籍中找到有关它的信息.
在大多数情况下,您应该初始化成员初始化列表中的所有成员对象(但是,请注意FAQ条目末尾列出的例外情况).
FAQ条目的主要内容是,
在所有其他条件相同的情况下,如果使用初始化列表而不是赋值,则代码将运行得更快.
Jos*_*osh 16
这是构造函数的初始化.这是在类构造函数中初始化成员的正确方法,因为它可以防止调用默认构造函数.
考虑这两个例子:
// Example 1
Foo(Bar b)
{
bar = b;
}
// Example 2
Foo(Bar b)
: bar(b)
{
}
Run Code Online (Sandbox Code Playgroud)
在示例1中:
Bar bar; // default constructor
bar = b; // assignment
Run Code Online (Sandbox Code Playgroud)
在示例2中:
Bar bar(b) // copy constructor
Run Code Online (Sandbox Code Playgroud)
这完全取决于效率.
另一个已经向您解释过,您观察到的语法称为"构造函数初始化列表".此语法允许您自定义初始化类的基础子对象和成员子对象(而不是允许它们默认初始化或保持未初始化).
我只想指出,正如你所说,"看起来像构造函数调用"的语法不一定是构造函数调用.在C++语言中,()语法只是初始化语法的一种标准形式.对于不同类型,它的解释不同.对于具有用户定义的构造函数的类类型,它意味着一件事(它确实是构造函数调用),对于没有用户定义的构造函数的类类型,它意味着另一件事(所谓的值初始化)为空())和非类类型它再次意味着不同的东西(因为非类型没有构造函数).
在您的情况下,数据成员具有类型int.int不是类类型,因此它没有构造函数.对于类型,int这种语法意味着简单地" bar用值"初始化num"就是这样.它就是这样完成的,直接,没有涉及的构造函数,因为,再次,int它不是类类型,因此它不能有任何构造函数.
我不知道你怎么会错过这个,这是非常基本的.这是初始化成员变量或基类构造函数的语法.它适用于普通的旧数据类型以及类对象.
这是一个初始化列表.它将在构造函数体运行之前初始化成员.考虑
class Foo {
public:
string str;
Foo(string &p)
{
str = p;
};
};
Run Code Online (Sandbox Code Playgroud)
VS
class Foo {
public:
string str;
Foo(string &p): str(p) {};
};
Run Code Online (Sandbox Code Playgroud)
在第一个示例中,str将由其无参数构造函数初始化
string();
Run Code Online (Sandbox Code Playgroud)
在Foo构造函数的主体之前.在foo构造函数里面,
string& operator=( const string& s );
Run Code Online (Sandbox Code Playgroud)
当你做str = p时,将在'str'上调用;
在第二个例子中,str将通过调用其构造函数直接初始化
string( const string& s );
Run Code Online (Sandbox Code Playgroud)
用'p'作为参数.
你是对的,这确实是一种初始化成员变量的方法.除了清楚地表明它是初始化之外,我不确定这有什么好处.在代码中包含"bar = num"可以更容易地移动,删除或误解.
它是构造函数的初始化列表.相反,默认构建的x,y并且z,然后指派他们在参数接收的值,这些成员将马上蝙蝠的值进行初始化.这对于floats 来说似乎并不是非常有用,但是对于构造成本昂贵的自定义类来说可能相当长.