题
我正在阅读这个C ++开源代码,我来到了一个构造函数但我没有得到它(基本上是因为我不知道C ++:P)
我非常了解C和Java。
TransparentObject::TransparentObject( int w, int x, int y, int z ) :
_someMethod( 0 ),
_someOtherMethod( 0 ),
_someOtherOtherMethod( 0 ),
_someMethodX( 0 )
{
int bla;
int bla;
}
到目前为止,我可以“演绎”第一行只声明construtor名称,“::”听起来像“属于”对我来说。而{}之间的代码是它自己的构造函数体。
我“思考”在参数和第一个“{”之后是什么?就像方法默认参数或东西,但我没有在网上找到合理的解释。我在示例中找到的大多数C ++构造函数几乎与Java中的相同。
我的假设是对的吗? " ::"就像属于,并且params和body之后的列表就像“default args”一样。还是什么?
<强>更新强> 谢谢你的回答。 那些被称为方法? (我猜不是)在构造函数体中调用它们的区别是什么
解决方案
最常见的情况是:
class foo{
private:
int x;
int y;
public:
foo(int _x, int _y) : x(_x), y(_y) {}
}
这会将 x
和 y
设置为构造函数中 _x
和 _y
中给出的值参数。这通常是构造声明为数据成员的任何对象的最佳方法。
您也可能正在查看构造函数链接:
class foo : public bar{
foo(int x, int y) : bar(x, y) {}
};
在这个例子中,类的构造函数将调用其基类的构造函数并传递值 x
和 y
。
进一步剖析功能:
TransparentObject::TransparentObject( int w, int x, int y, int z ) :
_someMethod( 0 ),
_someOtherMethod( 0 ),
_someOtherOtherMethod( 0 ),
_someMethodX( 0 )
{
int bla;
int bla;
}
::
-operator称为范围解析运算符。它基本上只表示 TransparentObject
是 TransparentObject
的成员。其次,假设构造函数的主体出现在花括号中,你是正确的。
更新:感谢您的回答。那些被称为方法? (我猜不是)在构造函数体中调用它们的区别是什么
有关此主题的更多信息比我可能给你的更多此处。您必须使用初始化列表的最常见区域是初始化引用或 const
时,因为这些变量必须在创建时立即赋值。
其他提示
你非常接近。第一行是声明。 ::左边的标签是类名,并且它是一个构造函数,函数名必须与类名相同。
TransparentObject::TransparentObject( int w, int x, int y, int z )
在C ++中,您可以选择在函数体开始之前为成员变量添加冒号和一些初始值。如果要初始化任何 const 变量或将参数传递给超类构造函数,则必须使用此技术。
:
_someMethod( 0 ),
_someOtherMethod( 0 ),
_someOtherOtherMethod( 0 ),
_someMethodX( 0 )
然后是花括号中构造函数的主体。
{
int bla;
int bla;
}
::实际上意味着包含(参见澄清的评论),但_someMethods等等所谓的初始化列表。 link =]
有很多信息 编辑:对不起,我的第一句话不正确 - 请参阅评论。是的,::是C ++范围操作符,它允许您告诉编译器函数属于什么。使用:在构造函数声明开始后,称为初始化列表。
参数列表和 {}
之间的代码指定了(某些)类成员的初始化。
初始化而不是赋值 - 它们是不同的东西---所以这些都是对构造函数的调用。
你是对的。它是一种为类变量设置默认值的方法。我不太熟悉它们之后的确切区别:在函数体中。
使用初始化列表通常有一些很好的理由。例如,您不能在构造函数的初始化列表之外设置成员变量。此外,如果成员变量需要其自己的构造函数的某些参数,则必须在此处传递它们。比较一下:
class A
{
public:
A();
private:
B _b;
C& _c;
};
A::A( C& someC )
{
_c = someC; // this is illegal and won't compile. _c has to be initialized before we get inside the braces
_b = B(NULL, 5, "hello"); // this is not illegal, but B might not have a default constructor or could have a very
// expensive construction that shouldn't be done more than once
}
到这个版本:
A::A( C& someC )
: _b(NULL, 5, "hello") // ok, initializing _b by passing these arguments to its constructor
, _c( someC ) // this reference to some instance of C is correctly initialized now
{}
在不使用初始化列表的情况下,所有类成员都将只调用其默认构造函数,因此这是唯一可以控制调用构造函数的位置(对于非动态分配的成员)。对于将调用哪个父类构造函数也是如此。
班级成员“初始化”在构造函数的主体内(即在使用=运算符的{}大括号之间)在技术上不是初始化,而是一个赋值。对于具有非平凡构造函数/析构函数的类,默认构造然后以这种方式通过赋值进行修改可能成本很高。对于参考成员,必须使用初始化列表,因为它们无法通过赋值运算符进行更改。
如果成员(或父类)没有默认构造函数,则无法在初始化列表中指定适当的构造函数将导致编译器生成错误。否则编译器将自己插入默认构造函数调用。对于内置类型,这没有任何作用,因此您将拥有垃圾值。
请注意,您在初始化列表中指定成员的顺序不会影响它们的调用顺序。它始终是父类构造函数(如果有),然后是类成员在类定义中定义它们的顺序。您将它们放在初始化列表中的顺序无关紧要,可能是微妙错误的来源......
在下面的设计示例中,看起来意图是使用值
初始化 m_b
,然后使用 m_b
m_a >,但实际发生的是 m_a
是用 m_b
(它本身尚未初始化)初始化的,然后用初始化
m_b
值代码>。 m_b
只包含垃圾!
struct BadInitialiserListExample
{
BadInitialiserListExample(int value) :
m_b(value),
m_a(m_b) // <-- *BUG* this is actually executed first due to ordering below!
{
}
int m_a;
int m_b;
};