初始化类

时间:2015-09-30 07:27:55

标签: c++ class initialization

我提前道歉,因为我的一些措辞可能不是100%正确。

我会有一个这样的课程:

class ClassName {
private:
    AnotherClass class2;
public:
  ClassName();
  ~ClassName();
...

在这个类的构造函数中,除了别的以外,我把行

ClassName::ClassName() {
    AnotherClass class2; 
}

我认为你应该用C ++初始化对象,但是我注意到(通过GDB)正在创建两个AnotherClass对象。一旦进入构造函数定义,然后再次在我的初始化行上。这背后的原因是什么?如果我想使用像AnotherClass(int a, int b)这样更复杂的构造函数,它会创建一个临时对象,然后在不久之后创建正确的对象,该怎么办?

5 个答案:

答案 0 :(得分:5)

AnotherClass class2;在构造函数体内创建另一个本地对象,它在体的末尾被销毁。这不是类成员的初始化方式。

类成员在构造函数签名和正文之间的成员初始化列表中的构造函数体之前初始化,从:开始,如下所示:

ClassName::ClassName() :
    class2(argumentsToPassToClass2Constructor),
    anotherMember(42) // just for example
{
    /* constructor body, usually empty */
}

如果您不想将任何参数传递给class2构造函数,则不必将其放在初始化列表中。然后将调用它的默认构造函数。

如果您只想在所有类成员上调用默认构造函数,则可以(并且应该)完全省略构造函数。隐式生成的默认构造函数将执行您想要的操作。

答案 1 :(得分:2)

您在构造函数中正在做的是创建另一个变量,仅在构造函数内部创建。

实际上,如果你什么也不做,AnotherClass对象中的默认构造函数将被调用。

如果要显式,可以使用构造函数初始化列表:

class2

如果您需要这样做,最后一种方法也是您使用ClassName::ClassName() : class2() { } 中的参数调用特定构造函数的方式。

答案 2 :(得分:2)

AnotherClass

如果class2具有默认构造函数,则编译器将为ClassName::ClassName() : class2(arguments) 对象调用它。

如果你想调用参数化构造函数,那么你将按照以下方式进行:

// Without Initializer List
class MyClass {
    Type variable;
public:
    MyClass(Type a) {  // Assume that Type is an already
                     // declared class and it has appropriate 
                     // constructors and operators
      variable = a;
    }
};

为何使用以及如何使用初始化列表:

考虑以下示例:

Type

此处编译器遵循以下步骤来创建MyClass类型的对象

  1. 首先为“a”调用Type的构造函数。
  2. 在MyClass()构造函数体内调用“Type”的赋值运算符

    变量= a;

  3. 最后,“a”的析构函数被称为“MyClass”,因为它超出了范围。

  4. 现在考虑使用带有初始化列表

    // With Initializer List class MyClass { Type variable; public: MyClass(Type a):variable(a) { // Assume that Type is an already // declared class and it has appropriate // constructors and operators } }; ()构造函数的相同代码
    Type

    使用初始化列表,以下步骤后面是编译器:

    1. 调用“variable(a)”类的复制构造函数来初始化:variable。初始化列表中的参数用于直接复制构造“Type”。
    2. a”的析构函数被称为“img”,因为它超出了范围。
    3. 正如我们从这个例子中看到的,如果我们在构造函数体内使用赋值,则有三个函数调用:constructor + destructor +一个附加赋值操作符调用。如果我们使用Initializer List,则只有两个函数调用:copy constructor + destructor call。

      这种分配惩罚将更多地存在于“真实”应用中,其中会有许多这样的变量。

      更多场景,您只需要使用初始化列表:

      1. 只能使用初始化列表调用基类的参数化构造函数。
      2. 用于初始化参考成员
      3. 用于初始化非静态const数据成员

答案 3 :(得分:0)

您只是在此行中创建一个局部变量。通常,有三种方法可以初始化私有成员:

  1. 默认初始化
  2. 如果你的构造函数没有做任何事情,编译器会通过调用默认构造函数(没有参数的ctr)自动初始化私有成员

    1. 将它们分配给ctr正文中的值
    2. 在这种情况下,您必须使用赋值运算符为私有成员分配所需的值。

      ClassName::ClassName()
      {
          class2 = AnotherClass(a, b, c); // if the class ctr has some parameters
      }
      
      1. 使用初始化列表
      2. 在你的情况下,它将是:

        ClassName::ClassName()
            : class2(initial_value)
        {
        }
        

        这通常是初始化类私有成员的最佳和最有效的选项,因为您避免为传递的参数调用复制构造函数。除非复制ctr包含耗时的操作,否则这通常不是问题。同样适用于选项#2,在这种情况下,您可能会遇到与赋值运算符相同的问题

答案 4 :(得分:0)

您所做的是创建一个与您的成员同名的新变量,
通过这样做,你掩盖了你的成员变量 此外,在此过程中,您的成员构造函数在ClassName空初始化列表中以静默方式调用。

你可以通过两种方式发起课程:

    ClassName::ClassName(): class2() {}

或:

    ClassName::ClassName() {
        this->class2 = AnotherClass();
    }

第一种方式更好,有时必须。 如果您只为成员使用空构造函数,则除了性能之外,您不会看到差异,因为编译器默认在其初始化列表中初始化成员(":"之后的部分)如果你不这样做,他会默默地为你做...) 但是,如果您的成员没有空构造函数,例如:

    AnotherClass:: AnotherClass(int a, int b)

如果您尝试在初始化时使用第二种方法,您将收到如下消息:

error: constructor for 'Initiator' must explicitly initialize the member 'class2' which does not have a default constructor