Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/132.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 构造函数中这种奇怪的冒号成员(“:”)语法是什么?_C++_Syntax_Constructor_C++ Faq_Ctor Initializer - Fatal编程技术网

C++ 构造函数中这种奇怪的冒号成员(“:”)语法是什么?

C++ 构造函数中这种奇怪的冒号成员(“:”)语法是什么?,c++,syntax,constructor,c++-faq,ctor-initializer,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; } 这个奇怪的:巴纳姆是什么意思?它似乎以某种方式初始化了成员变量,但我以前从未见过这种语法。它看起来像一个函数/构造函数调用,

最近我看到了如下示例:

#include <iostream>

class Foo {
public:
  int bar;
  Foo(int num): bar(num) {};
};

int main(void) {
  std::cout << Foo(42).bar << std::endl;
  return 0;
}
这个奇怪的:巴纳姆是什么意思?它似乎以某种方式初始化了成员变量,但我以前从未见过这种语法。它看起来像一个函数/构造函数调用,但对于int?对我来说毫无意义。也许有人能启发我。顺便说一下,有没有其他类似的深奥的语言特征,你在普通的C++书籍中找不到?

它是一个成员初始化列表。你应该在任何网站上找到有关它的信息

但是,请注意FAQ条目末尾列出的例外情况

FAQ条目的要点是

在所有其他条件相同的情况下,如果使用初始化列表而不是赋值,代码运行速度会更快


您是对的,这确实是一种初始化成员变量的方法。我不确定这是否有什么好处,除了清楚地表示这是一个初始化。在代码中有一个bar=num可能更容易被移动、删除或误解。

我不知道你怎么会错过这个,它非常基本。这是初始化成员变量或基类构造函数的语法。它适用于普通的旧数据类型以及类对象。

这就是构造函数初始化。这是初始化类构造函数中成员的正确方法,因为它可以防止调用默认构造函数

考虑以下两个例子:

// Example 1
Foo(Bar b)
{
   bar = b;
}

// Example 2
Foo(Bar b)
   : bar(b)
{
}
在示例1中:

Bar bar;  // default constructor
bar = b;  // assignment
在示例2中:

Bar bar(b) // copy constructor

这一切都与效率有关。

这称为初始化列表。这是初始化类成员的一种方法。使用它比简单地将新值分配给构造函数体中的成员有很多好处,但是如果类成员是常量或引用,则必须对它们进行初始化。

这是一个初始化列表。它将在运行构造函数体之前初始化成员。 考虑

vs

在第一个示例中,str将由其无参数构造函数初始化

string();
string( const string& s );
在Foo构造函数的主体之前。在foo构造函数中

string& operator=( const string& s );
将像调用str=p一样调用“str”

在第二个示例中,str将由 调用其构造函数

string();
string( const string& s );

以“p”作为参数。

还有另一个“好处”


如果成员变量类型不支持null初始化,或者其引用不能进行null初始化,则您别无选择,只能提供一个初始化列表

另一个已向您解释过,您观察到的语法称为构造函数初始化器列表。此语法允许您自定义初始化类的基子对象和成员子对象,而不是允许它们默认初始化或保持未初始化状态

我只想指出,正如您所说,看起来像构造函数调用的语法不一定是构造函数调用。在C++语言中,语法只是初始化语法的一种标准形式。对于不同的类型,它有不同的解释。对于具有用户定义构造函数的类类型,它意味着一件事,它实际上是一个构造函数调用;对于没有用户定义构造函数的类类型,它意味着另一件事,即所谓的空;对于非类类型,它意味着另一件事,因为非类类型没有构造函数


在本例中,数据成员的类型为int。int不是类类型,因此它没有构造函数。对于int类型,该语法意味着只需使用num值初始化bar,就这样。它是这样做的,直接地,不涉及构造函数,因为,再一次,int不是的类类型,因此它不能有任何构造函数。

这不是晦涩难懂的,它是


基本上,在你的例子中,x将被初始化为x,y为y,z为z。

这是构造函数的初始化列表。与默认构造x、y和z,然后为它们分配参数中接收到的值不同,这些成员将立即用这些值初始化。这对于浮动来说似乎不是非常有用,但对于构造成本很高的自定义类来说,它可以节省很多时间

Foo(int num): bar(num)    

此构造在C++中被称为成员初始化器列表。 简单地说,它将您的成员栏初始化为值num

构造函数内部的初始化和赋值有什么区别? 成员初始化:

Foo(int num): bar{num} {}
成员分配:

使用成员初始值设定项列表初始化成员和在构造函数体中为其赋值之间有很大区别

当您通过成员初始值设定项列表初始化字段时,构造函数将被调用一次,并且对象将在一次操作中被构造和初始化

如果使用赋值,则字段将首先使用默认构造函数初始化,然后通过赋值运算符w重新赋值 第i个实际值

正如您所看到的,在后者中有一个额外的创建和分配开销,这对于用户定义的类来说可能是相当大的

Cost of Member Initialization = Object Construction 
Cost of Member Assignment = Object Construction + Assignment
后者实际上相当于:

Foo(int num) : bar() {bar = num;}
而前者仅相当于:

Foo(int num): bar(num){}
对于内置的代码示例或POD类成员,没有实际开销

何时必须使用成员初始值设定项列表? 如果出现以下情况,您将不得不使用成员初始值设定项列表:

您的类有一个引用成员 您的类有一个非静态常量成员或 您的类成员没有默认构造函数或 用于初始化基类成员或 当构造函数的参数名和数据成员名相同时,这实际上不是必须的 代码示例: 类MyClass{ 公众: //引用成员,必须在成员初始值设定项列表中初始化 int&i; int b; //非静态常量成员,必须在成员初始值设定项列表中初始化 常数int k; //构造函数的参数名b与类数据成员相同 //另一种方法是使用此->b引用数据成员 MyClassint a、int b、int c:ia、bb、kc{ //无成员初始值设定项 //这->b=b; } }; 类MyClass2:公共MyClass{ 公众: INTP; int-q; myclass2intx,inty,intz,intl,intm:MyClassx,y,z,pl,qm{} }; int main{ int x=10; int y=20; int z=30; MyClass objx,y,z; int l=40; int m=50; MyClass2 obj2x,y,z,l,m; 返回0; } MyClass2没有默认构造函数,因此必须通过成员初始值设定项列表对其进行初始化。 基类MyClass没有默认构造函数,所以要初始化其成员,需要使用成员初始值设定项列表。 使用成员初始值设定项列表时要注意的要点: 类成员变量总是按照它们在类中声明的顺序初始化

它们不会按照成员初始值设定项列表中指定的顺序进行初始化。 简而言之,成员初始化列表并不确定初始化的顺序


鉴于上述情况,保持成员初始化的顺序与在类定义中声明成员的顺序相同始终是一种良好的做法。这是因为编译器不会在两个顺序不同时发出警告,但相对较新的用户可能会将成员初始值设定项列表混淆为初始化顺序,并根据初始化顺序编写一些代码。

此线程中尚未提及:由于C++11,成员初始值设定项列表可以使用列表初始化。统一初始化,大括号初始化:

Foo(int num): bar{num} {}

它与其他上下文中的列表初始化具有相同的语义。

好处是它通常更有效。在某些情况下,比如当你有const成员变量或者是引用变量的成员变量时,你必须使用一个初始化列表。一个普通的C++书,不提这可能是一本C书,有人认为++在封面上看起来很酷……你在普通C++书籍中找不到。哦亲爱的现在扔掉你平常的C++书籍。不是在窗外——可能有人会捡到它。最好将其切碎,并将其回收利用。完成?现在请查阅一本新书。这一语言特点很难深奥。这是对象构造的一个相当重要的特性。事实上,远非深奥,您通常别无选择,只能使用初始值设定项列表。例如,如果您的类包含常量成员变量或引用,则必须使用initalizer列表。了解术语非常关键-我很嫉妒我没有想到它。使用init列表还有许多其他原因。特别是当初始化顺序很重要时。遗憾的是它有这么愚蠢的假函数调用语法。@mgb,初始化列表并不能确定初始化的顺序。成员变量的初始化顺序与它们在类中声明的顺序相同,即使这与构造函数的初始化顺序不同。@mgb:我不认为这是一种虚假的函数调用语法。它是初始化语法,如int i23;,std::vector emptyVec0;,std::矢量fullVec10,23。;,等等。当然,只有删除了类型,因为类型在成员声明中。@Martin:它没有函数调用语法,它有一个构造语法ala:new StringName。它比Fooint num:m_Count=5更适合构造函数。更不用说必须在此时构造类,因为它是在这里初始化的。Fooint num:Bar=num,无法正确编译。看到Fooint-num:m_-Countnum似乎很奇怪,因为基本类型并没有被构造。像这样写在声明中的一行中,很容易不把它作为init-list,我不会说这是关于效率的。它是关于提供一种方法来初始化需要初始化但不能默认初始化的东西。出于某种原因,人们以常量和引用为例
s、 最明显的例子是没有默认构造函数的类;在他的例子中,你可以为效率辩护;对于const/reference/no默认构造函数问题,它既有效率又有必要。因为它,我把下面的答案投了更高的票:[法恩斯沃思的声音]它可以做其他事情。为什么不应该呢?酒吧吧;//默认构造函数你确定吗?@LightnessRacesinOrbit只是想知道:你认为应该是什么?@nils这是目前为止最好的答案。Als指出的初始化顺序也非常重要,尽管VisualStudio编译器不会对此做任何说明,但其他编译器(如gcc)将失败。同样重要的是要注意,根据您的编译器和具体情况,这并不一定能提高性能或效率。@ryf9059:您认为这会带来什么不便?无论如何,你必须列出它们,所以为什么不按照声明的顺序排列呢?这应该是答案。谢天谢地,我向下滚动了一下,否则我会错过它。@AlokSave MyClassint a,int b,int c:ia,bb,kc{//没有成员初始值设定项//this->b=b;}它应该是这样的MyClassint&a,int b,int c:ia,bb,kc{//没有成员初始值设定项//this->b=b;}以及声明和调用中的相应更改。如果没有这个改变,我将引用a,但a不能引用x,因为它只包含x的值,所以间接地我不能引用x。所以如果我们修改i的值,那么它只修改a,而不是x@AbhishekMane你说得对,这里有一个相关问题的链接显示:@LightnessRacesinOrbit-Point,本贾尼·斯特劳斯特卢普在他的Tc++PL和C++编程语言中说,内置类型也有默认构造函数。还说内置类型有构造函数。我个人通过邮件向bjarne问了这个问题&他说是的,内置类型也有构造函数。所以你的答案是错误的@毁灭者:我的回答绝对正确。为了简化这本书,比亚恩·斯特劳斯特鲁普在书中故意、明确地撒了谎。比较TC++ + PL书的大小和C++语言标准的大小。看到区别了吗?TC++PL的相对紧凑性所付出的代价是显而易见的,每个人都知道错误和遗漏,正如您提到的,还有很多其他错误和遗漏。因此,更简洁地说:我的答案是正确的,TC++PL是错误的。但对于像你这样刚刚开始学习的人来说,TC++PL已经足够好了。请不要告诉我们关于你通过邮件向比亚恩提出这个问题的无稽之谈。这个问题也是众所周知的,很久以前就已经被详尽地讨论和解决了。但即使他对你说了那样的话,也没关系。最后,唯一重要的是语言规范说了什么。比亚恩·斯特劳斯特鲁普所说的是无关紧要的。你链接的Geeksforgek上的帖子完全是假的。那么,你认为标准是没有bug的吗?C++标准也有bug。@析构函数:当然,它确实如此。但是,该标准定义了该语言。根据定义,标准所说的一切都是绝对真理。它可能存在的唯一缺陷主要是与措辞相关的东西,如自相矛盾的措辞、含糊不清的措辞、不明确的措辞等等。这些错误被强烈地发现、报告、记录、讨论和解决。意图中的bug也可能存在,但这是一个有争议的问题。
Foo(int num): bar{num} {}