C++构造函数名后的冒号是做什么的?

spe*_*wah 85 c++ constructor initialization-list ctor-initializer

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

class MyClass {
public:

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

    int m_classID;
    void *m_userdata;
};
Run Code Online (Sandbox Code Playgroud)

Dan*_*nas 94

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

构造函数的签名是:

MyClass();
Run Code Online (Sandbox Code Playgroud)

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

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

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


Asi*_*sik 43

这是一个初始化列表.

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

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

如果其中一个字段是引用,则初始化列表是必需的,因为引用永远不能为空,即使在对象构造和构造函数体之间的短暂时间内也是如此.以下引发错误C2758:'MyClass :: member_':必须在构造函数base/member初始化列表中初始化

class MyClass {
public :
    MyClass(std::string& arg) {
        member_ = arg;
    }
    std::string& member_;
};
Run Code Online (Sandbox Code Playgroud)

唯一正确的方法是:

class MyClass {
public :
    MyClass(std::string& arg) 
        : member_(arg) 
    {
    }
    std::string& member_;
};
Run Code Online (Sandbox Code Playgroud)

  • 如果你有一个引用成员,那么你经常会误认为你有*定义一个带有构造函数初始化列表的构造函数.但那不是真的.一个简单的`MyClass m = {arg};`也可以正常工作. (2认同)
  • "如果在构造函数的主体中为它们赋值,则调用复制构造函数"不,你不是.复制赋值运算符与复制构造函数不同. (2认同)