类成员初始化差异

时间:2011-03-04 22:39:49

标签: c++

关于复数的类定义,我看到了两种类型的定义:

定义1

class Complex
{
   private:
      double re;
      double im;

   public:
      Complex(float r,float i) {re = r; im = i;}
      ~Complex() {};
};

定义2

class Complex
{
   private:
      double re;
      double im;

   public:
      Complex(double r,double i): re(r), im(i) {}
      ~Complex() {};
 };

第一个定义看起来不错,但我不太了解第二个定义,

 Complex(double r,double i): re(r), im(i) {}

工作? “re()”是什么意思?

5 个答案:

答案 0 :(得分:4)

它被称为初始化列表。在类的构造函数中,您可以使用此语法初始化成员变量。所以在这里,它等同于将语句re = r; im = i;放在构造函数的主体中。

对于POD变量(例如intdouble和指针类型),初始化列表语法与正文中的常规赋值之间没有区别。但是,对于const变量,引用和具有非平凡构造函数的对象,存在重要差异

  • 对于const变量和引用变量,它们必须在初始化列表中初始化。他们无法通过在身体中分配来进行初始化。
  • 对于具有非平凡构造函数的对象,如何在初始化列表中初始化它们对应于被调用的构造函数。如果省略变量,则调用该对象的默认构造函数(如果该对象没有默认构造函数,则表示编译器错误)。

因此,通常建议在初始化程序列表中初始化具有构造函数的对象以避免冗余工作 - 如果通过从初始化程序列表中省略它来让其默认构造函数运行,然后在构造函数中执行某种初始化身体,你要初始化两次,这可能是浪费。

例如:

class Example
{
private:
    std::string m_string;
public:
    Example()
    {
        // m_string is first initialized by the std::string default constructor,
        // then we assign to it with operator=(const char *).
        // This is inefficient.
        m_string = "test";
    }

    Example(int dummy)
        : m_string("test")
    {
        // Better: we just call the std::string(const char*) constructor directly
    }
};

答案 1 :(得分:2)

Complex构造函数的第二种形式使用initialization lists,它们是初始化类成员的不同(和preferred way)。

re(...)意味着成员字段re应该使用它传递的任何参数构建。

作为另一个例子 - 您可以像这样创建doubleint等基元:

double d(5.0d);
int i(5);

哪个应该解释括号如何在列表中工作。

答案 2 :(得分:1)

这是一个初始化列表。它将re的值设置为r,将im的值设置为i

通常,您会通过使用初始化列表看到性能提升,但知道何时不使用它也很重要。

答案 3 :(得分:1)

首先,在C ++中的整个类定义之后应该有一个分号。否则你的代码将公平地编译。

无论如何,

Complex(double r,double i): re(r), im(i) {}

是Complex类的构造函数,它只是将r的值放入re,将i的值放入im。这是初始化类值的另一种方法。

请注意,像这样的初始化列表对于初始化类中的成员类非常有用。这是一个例子:

class MemberClass
{
    private:
        int mValue;

    public:
        MemberClass(int value): mValue(value) {}
};

class MemberHolder
{
    private:
        MemberClass mMember;

    public:
        MemberHolder(int value): mMember(value) {}
};

初始化列表对于在其他类中使用没有默认构造函数的类非常重要。

答案 4 :(得分:1)

在C ++中,赋值和初始化之间存在区别。

a = 5;  // assignment
int b = 6; // initialization
int b(6);  // also initialization

您的类的第一个版本在构造函数的主体内执行赋值。这样更昂贵,因为数据成员reim首先是默认构造的,然后分配它们的值。

在第二个版本中使用构造函数初始化列表。这里使用提供的值初始化数据成员。这一步发生,而默认构造函数+赋值是两步。这样效率更高。

通常,您应该更喜欢在初始化列表中初始化数据成员,以在构造函数的主体内分配它们的值。但是有一个警告。初始化列表中的数据成员按照它们在类中声明的顺序进行初始化,而不是按照它们在初始化列表中出现的顺序进行初始化。通常,您希望列表中的成员顺序与其声明顺序相匹配。否则,如果一个数据成员的初始化取决于另一个数据成员的值,则最终可能很难找到错误。