【问题标题】:What does a colon following a C++ constructor name do? [duplicate]C++ 构造函数名称后面的冒号有什么作用? [复制]
【发布时间】:2010-11-19 08:24:36
【问题描述】:

这个构造函数中的冒号运算符(“:”)有什么作用?是否等同于MyClass(m_classID = -1, m_userdata = 0);

class MyClass {
public:

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

    int m_classID;
    void *m_userdata;
};

【问题讨论】:

    标签: c++ constructor initialization-list ctor-initializer


    【解决方案1】:

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

    构造函数的签名是:

    MyClass();
    

    这意味着可以不带参数调用构造函数。这使它成为一个默认构造函数,即当你写MyClass someObject;时默认调用的构造函数。

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

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

    【讨论】:

      【解决方案2】:

      这是一个初始化列表。

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

      因此,对于像 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_;
      };
      

      【讨论】:

      • 人们经常错误地认为,如果你有一个引用成员,你必须定义一个带有构造函数初始化列表的构造函数。但这并不完全正确。一个简单的MyClass m = { arg }; 也可以正常工作。
      • litb: 但是你或多或少需要使用 m = {arg};你不是吗?在我看来,能够做 MyClass m(ref) 是非常需要的。
      • @Skurmedel,我同意。但这并不意味着它是唯一的方法,当然。
      • "如果你在构造函数的主体中为它们赋值,你调用的是复制构造函数"不,你不是。复制赋值运算符不同于复制构造函数。
      • 这个答案是错误的。我投票删除它。每个人都应该-1。显然,这让新来者感到困惑 (stackoverflow.com/questions/28529416/…)。
      【解决方案3】:

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

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

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

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

          【解决方案5】:

          这是一个initialization list。在您的示例中,它有点像这样(像这样 - 并不意味着它在所有情况下都是等效的):

          
          class MyClass {
          
          public:
          
              MyClass(){
                   m_classID = -1;
                   m_userdata = 0;
              }
          
              int m_classID;
              void *m_userdata;
          
          };

          【讨论】:

            【解决方案6】:

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

            在这种情况下,它将m_classID 初始化为-1,将m_userData 初始化为NULL。

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

            【讨论】:

            • 有时也必须使用成员初始化列表。如果你有一个引用的成员变量,你必须使用成员初始化列表来设置它。
            【解决方案7】:

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

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

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

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

            【讨论】:

              【解决方案8】:

              它是一个初始化列表的开始,它在对象的构造过程中设置成员变量。您的示例“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;
              }
              

              谷歌了解更多信息。

              【讨论】:

                【解决方案9】:

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

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

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2011-03-31
                  • 2011-06-24
                  • 2020-03-27
                  • 2019-07-14
                  • 2016-10-13
                  • 2018-10-20
                  • 2011-01-21
                  相关资源
                  最近更新 更多