C++构造函数问题
在C++编程绝对初学者,第二版书中,有以下陈述:
HeapPoint::HeapPoint(int x, int y): thePoint(new Point(x,y)) { }
这是否等于:
HeapPoint::HeapPoint(int x, int y) { thePoint = new Point(x,y); }
并且,由于我们在构造函数中执行此操作,为分配的值是多少>x
和 y
?我们应该在 new Point(x,y)
中写入由 x
和 y
代替的值吗?或者说,这样是正确的吗?
更新:我想我得到了初始化x
和y
的想法,因为在书中它在函数中具有以下内容:
HeapPoint myHeapPoint(2,4);
In the C++ programming for the absolute Beginner, 2nd edition book, there was the following statement:
HeapPoint::HeapPoint(int x, int y): thePoint(new Point(x,y)) { }
Is this equal to:
HeapPoint::HeapPoint(int x, int y) { thePoint = new Point(x,y); }
And, since we are doing this in a constructor, what are the values assigned for x
and y
? Should we write values insted of x
and y
in new Point(x,y)
? Or, it is correct that way?
UPDATE: I think I got the idea of initializing x
and y
, as in the book it has the following in a function:
HeapPoint myHeapPoint(2,4);
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
一般来说,您应该更喜欢第一个构造,即使用初始化列表。
如果
Generally you should prefer the first construct, i.e. using the initialiser list.
The second construct is preferable if
假设 thePoint 是一个原始指针,无论其意图和目的如何,它都是相同的。第一个版本初始化
thePoint
,而第二个版本则对其进行赋值,但效果几乎总是相同的,甚至生成完全相同的机器代码。他们什么时候不一样了?
thePoint
是多个成员变量之一时,第一种形式将按照它在类定义中出现的顺序对其进行初始化,而第二种形式将在构造函数的主体中进行赋值。因此,两种形式之间“水合”的顺序可能有所不同,如果某些成员变量依赖于其他成员变量,这可能很重要。如果您是初学者,其中大部分内容可能对您来说毫无意义。但不用担心。这些差异非常微妙,几乎永远不会产生影响。 (我确信还有其他例外,但现在还没有想到。)
这最终是风格和一致性的问题,为此我更喜欢初始化形式而不是赋值形式。
Assuming
thePoint
is a raw pointer, it is, for all intents and purposes, the same. The first version initialisesthePoint
, whereas the second assigns to it, but the effect is almost always the same, even to the point of generating exactly the same machine code.When aren't they the same?
thePoint
is some kind of smart pointer, the first form will initialise it by passing the new Point to its constructor, whereas the second form will probably zero-initialise it and then pass the new Point to its assignment operator.thePoint
is one of several member variables, the first form will initialise it in the order it appears in the class definition, whereas the second form will assign in the body of the constructor. So the order in which things get "hydrated" may vary between the two forms, which may matter if some members variables depend on others.If you are a beginner, most of this is probably meaningless to you. But don't worry about it. These differences are very subtle and will almost never matter. (I'm sure there are other exceptions, but none come to mind just now.)
It's ultimately a matter of style and consistency, for which I prefer the initialisation form over the assignment form.
这两种形式并不完全相同,因为初始化列表给出了一个直接放入变量中的值,而变量则在适当的情况下默认初始化(例如 std::strings 默认为空,但 int、double等(成员变量具有有效的随机值),然后在遇到赋值操作时被覆盖。这种覆盖可能效率较低,但对于某些在创建后不允许更改的常量和引用成员变量来说也可能是非法的。一般来说,只要有可能就使用初始化列表,这样就不会出错。只有当您发现由于需要先执行其他一些步骤而无法初始化某些内容时,才应该在构造函数体内放置显式赋值语句。请注意,初始化按照成员变量在类中声明的顺序进行,无论您在构造函数本身中列出它们的顺序如何:好的编译器(例如 GCC)可以对此发出警告。
The two forms aren't quite the same in that the initialisation list gives a value to be placed directly into the variable, whereas the variables are otherwise default-initialised if appropriate (e.g. std::strings are empty by default, but int, double etc. member variables have effectively random values), then overwritten when the assignment operation is encountered. This overwriting can be less efficient, but it can also be illegal for some constant and reference member variables that aren't allowed to be changed after they're created. In general, use the initialiser list whenever possible and you won't go far wrong. Only when you find you can't initialise something yet because you need to do some other steps first should you put an explicit assignment statement inside the constructor body. Be aware the initialisations take place in the order in which the member variables are declared in the class, irrespective of the order you list them in the constructor itself: a good compiler (e.g. GCC) can warn you about this.
第一个与第二个不一样。
在这种特定情况下,它们可能会产生相同的结果。 但是,Point可以轻松地为
new Point
实现赋值运算符并做一些“不同”的事情(我没有这本书,所以我不知道每一个细节)。同样,赋值运算符应该做你所期望的......但是,thePoint可能是一个容器(例如,智能指针),它可以(由于某些奇怪的原因) ) 使用初始化(Point)
与默认初始化后赋值
时的行为有所不同。在这种情况下,这些细节可能并不重要,但它们确实会影响初始化顺序和执行。当您的程序增长时,这种差异将变得很重要。那时,初始化需要时间,并且您需要确保对象正确初始化:它们被正确构造(第一次)并且它们以正确的顺序构造。最明显的情况:当默认构造函数的行为与带参数的构造函数不同时,特别是当构造函数产生分配或具有其他耗时(或行为不同)的副作用时,它将产生影响。
这完全取决于
Point
的构造函数。首选方法(对于大多数团队来说)是尽可能使用初始化列表和正式构造函数,并编写类型以支持正确的初始化。当代码库增长时,会出现很多微妙之处。此构造函数使用初始化列表:
HeapPoint::HeapPoint(int x, int y): thePoint(new Point(x,y)) { }
如果您愿意,在假设的情况下可能需要正确的初始化像这样声明 thePoint:
const Point* const thePoint;
第一个
const
意味着您不能修改 Point(例如,Point.x
或Point.y
)。第二个 const 意味着您不能为该变量分配新的分配。 OP 中的示例是简单的示例,但随着程序的增长绝对有帮助。the first is not the same as the second.
in this specific case, they will probably produce the same result. however, Point could easily implement an assignment operator for
new Point
and do something 'different' (i don't have the book, so i don't know every detail). as well, the assignment operator should do what you'd expect... however, thePoint could be a container (e.g., smart pointer) which could (for some odd reason) behave differently when usinginitialization(Point)
vsdefault initialization followed by assignment
.these details likely won't matter in this case, but they do affect initialization order, and the execution. the difference will be important when your programs grow. at that time, initialization will take time, and you will want to ensure that the objects are initialized correctly: that they are constructed properly (the first time) and that they are constructed in the right order. most obvious case: it will make a difference when a default constructor behaves different from one with parameters, especially when the constructor produces allocations or has other time-consuming (or behaviorally different) side effects.
that depends entirely on
Point
's constructor.the preferred way (for most teams) is to use the initialization list and formal constructors wherever possible, and to write your types to support correct initialization. there are a lot of subtleties that come out when codebases grow. this constructor uses the initialization list:
HeapPoint::HeapPoint(int x, int y): thePoint(new Point(x,y)) { }
proper initialization could in a hypothetical case be required if you want to declare thePoint like so:
const Point* const thePoint;
the first
const
means that you cannot modify the Point (e.g.,Point.x
orPoint.y
). the second const means that you cannot assign a new allocation to the variable. trivial examples for the example in the OP, but definitely helpful as your programs grow.在第一种情况下,您使用初始化列表来设置成员
thePoint
,而在第二个示例中,您使用构造函数的主体。后面完成的工作是不一样的,因为初始化列表是在构建对象之前使用的,一旦完成,就会使用构造函数主体。因此:
thePoint(new Point(x,y))
构建的
在第二种情况下,它可能是第一个分配的因为它有一个默认的构造函数,然后构建的对象将被主体中的调用覆盖(是的,相同的一个,但不在同一位置)!!所以你在这里失去了效率。
如果存在初始化列表,这是有充分理由的(C++ 是一种非常精确的语言,语法非常严格,除了来自 C 的丑陋的东西之外,一切都是合乎逻辑的)!例如,如果您的类使用了引用成员,则您必须使用初始化列表,因为您的对象不会完全构建:
请记住,这里,如果我们完成了
_c(c), _b( b)
在第一个构造函数中(相反顺序),类B
和C
的复制构造函数无论如何都会以相同的顺序调用:它们被称为 按照定义成员的顺序(即_b
在_c
之前),而不是您编写它们的顺序!!!!In your 1st case, you use an initialization list to setup your member
thePoint
, whereas in your 2nd example you use the body of the constructor. The work done behind is not the same, since initialization lists are used before your object is built, and once this is finished your constructor body is used.So:
in your 1st case, your member
thePoint
is directly built withthePoint(new Point(x,y))
in the 2nd case it is first allocated probably because a default constructor is available for it, then the object built is overridden with the call made in the body (yes, the same one, but not at the same place) !! So you lost efficiency here.
If initialization lists exist, this is for good reasons (C++ is a very precise language, the syntax is really strict, except for ugly things coming from C all is logical) ! For instance if your class used a reference member, you'd be obliged to use an initialization list, since your object would not be entirely built:
Keep in mind that here, if we had done
_c(c), _b(b)
in the 1st contructor (reverse order), copy constructors of classesB
andC
would be called in the same order anyway: they are called in the order the members are defined (i.e._b
before_c
), not the order you write them !!!!两者都是一样的。第一种情况:
使用
thePoint
所属类的构造函数,并使其指向为Point
新分配的内存。第二种情况也是分配内存,其地址分配给
thePoint
Both are same. The first case:
uses the constructor of the class to which
thePoint
belongs, and makes it point to a new allocated memory forPoint
.The second case also assigns the memory, and its address is assigned to
thePoint