我正在阅读这个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;
};
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top