构造函数中冒号之后的成员变量列表是什么?

时间:2008-10-16 23:20:33

标签: c++ constructor

我正在阅读这个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”之类的东西?

更新 谢谢你的回答。 那些被称为方法? (我猜不是)在构造函数体中调用它们的区别是什么

8 个答案:

答案 0 :(得分:19)

最常见的情况是:

class foo{
private:
    int x;
    int y;
public:
    foo(int _x, int _y) : x(_x), y(_y) {}
}

这会将xy设置为构造函数参数中_x_y中给出的值。这通常是构造声明为数据成员的任何对象的最佳方法。

您也可能正在查看构造函数链接:

class foo : public bar{
    foo(int x, int y) : bar(x, y) {}
};

在这个例子中,类的构造函数将调用其基类的构造函数并传递值xy

进一步剖析功能:

TransparentObject::TransparentObject( int w, int x, int y, int z ) : 
   _someMethod( 0 ),
   _someOtherMethod( 0 ),
   _someOtherOtherMethod( 0 ),
   _someMethodX( 0 ) 
{
     int bla;
     int bla;
}

:: - 运算符称为范围解析运算符。它基本上只表示TransparentObjectTransparentObject的成员。其次,假设构造函数的主体出现在花括号中,你是正确的。

  

更新:感谢您的回答。那些被称为方法? (我猜不是)在构造函数体中调用它们的区别是什么

关于这个主题的信息比我可能给你的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_bvalue只会包含垃圾!

m_b