100

冒号运算符 (":") 在这个构造函数中做了什么?是否相当于MyClass(m_classID = -1, m_userdata = 0);

class MyClass {
public:

    MyClass() : m_classID(-1), m_userdata(0) { 
    }

    int m_classID;
    void *m_userdata;
};
4

9 回答 9

109

这是一个初始化列表,是构造函数实现的一部分。

构造函数的签名是:

MyClass();

这意味着可以在没有参数的情况下调用构造函数。这使它成为默认构造函数,即在您编写时默认调用的构造函数MyClass someObject;

该部分 : m_classID(-1), m_userdata(0)称为初始化列表。这是一种使用您选择的值初始化对象的某些字段(如果需要,所有字段)的方法,而不是将它们保留为未定义。

执行初始化列表后,构造函数主体(在您的示例中恰好为空)被执行。在它里面你可以做更多的分配,但是一旦你输入了它,所有的字段都已经被初始化了——要么是随机的、未指定的值,要么是你在初始化列表中选择的那些。这意味着您在构造函数主体中所做的分配将不是初始化,而是值的更改。

于 2009-08-13T15:26:45.613 回答
48

这是一个初始化列表。

当你进入构造函数的主体时,所有字段都已经构造好了;如果他们有默认构造函数,那些已经被调用了。现在,如果您在构造函数的主体中为它们分配一个值,您将调用复制赋值运算符,这可能意味着释放和重新获取资源(例如内存)(如果对象有任何资源)。

因此,对于像 int 这样的原始类型,与在构造函数的主体中分配它们相比没有优势。对于具有构造函数的对象,这是一种性能优化,因为它避免了通过两个对象初始化而不是一个。

如果其中一个字段是引用,则初始化列表是必要的,因为引用永远不能为空,即使在对象构造和构造函数主体之间的短暂时间内也是如此。以下引发错误 C2758:“MyClass::member_”:必须在构造函数基/成员初始化程序列表中初始化

class MyClass {
public :
    MyClass(std::string& arg) {
        member_ = arg;
    }
    std::string& member_;
};

唯一正确的方法是:

class MyClass {
public :
    MyClass(std::string& arg) 
        : member_(arg) 
    {
    }
    std::string& member_;
};
于 2009-08-13T15:37:00.043 回答
3

它表示初始化列表的开始,用于初始化对象的成员变量。

至于:MyClass(m_classID = -1, m_userdata = 0);

这声明了一个可以接受参数的构造函数(所以我可以创建一个MyClassusing MyClass m = MyClass(3, 4),这将导致m_classID3 和m_userdata4)。如果我不向MyClass构造函数传递任何参数,则会导致为具有初始化列表的版本创建等效对象。

于 2009-08-13T15:25:24.740 回答
2

它表示初始化列表的开始。

它也不等同于 MyClass(m_classId=-1,m_userData=0)。这是试图定义一个具有 2 个具有默认值的参数的构造函数。但是,这些值缺少类型,根本不应该编译。

于 2009-08-13T15:27:07.437 回答
1

这是一个初始化列表。在您的示例中,它有点像这样(这样的东西 - 并不意味着它在所有情况下都是等价的):


class MyClass {

public:

    MyClass(){
         m_classID = -1;
         m_userdata = 0;
    }

    int m_classID;
    void *m_userdata;

};
于 2009-08-13T15:26:44.257 回答
1

也就是所谓的成员初始化列表。它用于调用超类构造函数,并在创建成员变量时为其赋予初始值。

在这种情况下,它初始化m_classID为 -1 和m_userDataNULL。

它并不完全等同于在构造函数的主体中进行赋值,因为后者首先创建成员变量,然后对其进行赋值。有了初始化,在创建的时候就提供了初始值,所以在复杂对象的情况下,可以更加高效。

于 2009-08-13T15:27:32.523 回答
1

它不完全是一个运算符。它是构造函数语法的一部分。

它的意思是,后面将是成员变量及其初始值的列表。

必须以这种方式初始化常量成员。非常量也可以在这里初始化,只要它可以用一个表达式来完成。如果需要更多代码来初始化成员,则必须在 {} 之间放置实际代码才能执行此操作。

很多人喜欢将几乎所有的构造函数代码都放在初始化器列表中。我有一位同事经常用几个屏幕的初始化程序编写类,然后将“{}”用于构造函数代码。

于 2009-08-13T15:28:00.977 回答
1

它是一个初始化列表的开始,它在对象的构造过程中设置成员变量。您的示例“MyClass(m_classID = -1, m_userdata = 0);” 不可能,因为您没有定义正确的构造函数,并且无论如何您都无法访问参数列表中的成员变量......您可能会有类似的东西:

MyClass( int classId = -1, void* userData = 0 ) : m_classID(classId), m_userdata(userData) {}

初始化器列表被认为优于:

MyClass( int classId = -1, void* userData = 0 ) {
    m_classID = classId;
    m_userdata = userData;
}

谷歌了解更多信息。

于 2009-08-13T15:29:19.493 回答
0

在这种情况下:是的,ist 是等价的,因为只涉及原始类型。

如果成员是类(结构),那么您应该更喜欢初始化列表。这是因为否则对象是默认构造然后分配的。

于 2009-08-13T15:25:46.893 回答