我正在阅读这个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之后的列表就像“默认args”之类的东西?
更新 谢谢你的回答。 那些被称为方法? (我猜不是)在构造函数体中调用它们的区别是什么
答案 0 :(得分:19)
最常见的情况是:
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;
}
::
- 运算符称为范围解析运算符。它基本上只表示TransparentObject
是TransparentObject
的成员。其次,假设构造函数的主体出现在花括号中,你是正确的。
更新:感谢您的回答。那些被称为方法? (我猜不是)在构造函数体中调用它们的区别是什么
关于这个主题的信息比我可能给你的here要多得多。您必须使用初始化列表的最常见区域是初始化引用或const
时,因为这些变量必须在创建后立即赋值。
答案 1 :(得分:10)
你非常接近。第一行是声明。 ::左边的标签是类名,并且它是一个构造函数,函数名必须与类名相同。
TransparentObject::TransparentObject( int w, int x, int y, int z )
在C ++中,您可以选择在函数体开始之前为成员变量添加冒号和一些初始值。如果要初始化任何 const 变量或将参数传递给超类构造函数,则必须使用此技术。
:
_someMethod( 0 ),
_someOtherMethod( 0 ),
_someOtherOtherMethod( 0 ),
_someMethodX( 0 )
然后是花括号中构造函数的主体。
{
int bla;
int bla;
}
答案 2 :(得分:7)
::实际上意味着包含(请参阅注释以澄清),但是_someMethods等等就是所谓的initialisation list。 link =]
有很多信息 编辑:对不起,我的第一句话不正确 - 请参阅评论。答案 3 :(得分:2)
是的,::是C ++范围操作符,它允许您告诉编译器函数属于什么。使用:在构造函数声明开始后,称为初始化列表。
答案 4 :(得分:2)
参数列表和{}
之间的代码指定了(某些)类成员的初始化。
初始化而不是赋值 - 它们是不同的东西---所以这些都是对构造函数的调用。
答案 5 :(得分:1)
你是对的。它是一种为类变量设置默认值的方法。我不太熟悉它们之后的确切区别:在函数体中。
答案 6 :(得分:1)
使用初始化列表通常有一些很好的理由。例如,您不能在构造函数的初始化列表之外设置成员变量。此外,如果成员变量需要其自己的构造函数的某些参数,则必须在此处传递它们。比较一下:
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
{}
答案 7 :(得分:0)
在不使用初始化列表的情况下,所有类成员都将只调用其默认构造函数,因此这是唯一可以控制调用构造函数的位置(对于非动态分配的成员)。对于将调用哪个父类构造函数也是如此。
在构造函数体内(即使用=运算符在{}括号之间)“初始化”的类成员在技术上不是初始化,而是一个赋值。对于具有非平凡构造函数/析构函数的类,默认构造然后以这种方式通过赋值进行修改可能成本很高。对于参考成员,必须使用初始化列表,因为它们无法通过赋值运算符进行更改。
如果成员(或父类)没有默认构造函数,则无法在初始化列表中指定适当的构造函数将导致编译器生成错误。否则编译器将自己插入默认构造函数调用。对于内置类型,这没有任何作用,因此您将拥有垃圾值。
请注意,您在初始化列表中指定成员的顺序不会影响它们的调用顺序。它始终是父类构造函数(如果有),然后是类成员在类定义中定义它们的顺序。您将它们放在初始化列表中的顺序无关紧要,可能是微妙错误的来源......
在下面的设计示例中,看起来意图是使用m_b
然后使用value
m_a
初始化m_b
,但实际发生的是{{1} }使用m_a
进行初始化(其本身尚未初始化),然后使用m_b
初始化m_b
。 value
只会包含垃圾!
m_b