【问题标题】:C++ method declaration questionC++方法声明问题
【发布时间】:2010-11-17 06:23:51
【问题描述】:

我在 Image.cpp 中有一些代码:

Image::Image( int width, int height, int depth ) : m_sFileName(0)  
{  
...  
}  

and in Image.h:  
class Image: public DrawAble, public RenderAble  
{  
...  
private :  
    std::string *m_sFileName;  
};  

我的问题是:第一行中的m_sFilename 发生了什么?我想它被设置为 NULL 但这样做有什么意义。会不会也是这样:

Image::Image( int width, int height, int depth )  
{  
    m_sFileName(0);  
...  
}

【问题讨论】:

    标签: c++ syntax methods declaration


    【解决方案1】:

    这称为初始化程序。你应该习惯使用它们。在这种情况下,这无关紧要。但在其他情况下,不使用它们可能意味着非指针成员的双重初始化。首先使用默认值,然后使用您的值。 最后是成员没有没有参数的构造函数的情况。在这些情况下,您别无选择,只能使用初始化程序。

    【讨论】:

      【解决方案2】:

      这两个变体几乎相同——你说得对

      : m_sFileName(0)
      

      导致m_sFileName 被初始化为0

      当您想创建const Image 时,C++ 具有这种特殊初始化语法的原因变得很重要。 (在这种情况下可能不是您想要做的事情,但它可以是您可能想要为“轻量级”类型做的事情。)对于const Imagethis 是构造函数中的 const 指针以及每个“ normal" 成员函数,因此不允许使用m_sFileName=0

      为了解决这个问题,C++ 有初始化列表,它执行初始化,而不是赋值。顺便说一句,如果m_sFileName 是一个对象,那么除了const 的注意事项之外,还有一个额外的区别:初始化列表会导致调用m_sFileName 的构造函数,而赋值会调用赋值运算符。

      除了所有这些考虑因素之外,初始化列表是一种传达意图的好方法——表明您正在初始化,而不是分配。

      【讨论】:

        【解决方案3】:

        第一个使用所谓的initialization list

        当你进入构造函数的主体时,所有的类成员必须已经被构造(所以它们可以被使用)。所以如果你有这个:

        class Foo
        {
        public:
            Foo()
            : str() // this is implicit
            {
                str = "String.";
            }
        private:
            std::string str;
        };
        

        所以,str 被构造,然后被分配。更好的是:

        class Foo
        {
         public:
            Foo()
            : str("String.")
            {
            }
        private:
            std::string str;
        };
        

        这样str 就被直接构造了。这对您的情况没有影响,因为指针没有构造函数。

        在构造函数中使用初始化列表而不是正在运行的代码通常被认为是一种很好的做法。 初始化列表应该用于初始化,构造函数应该用于运行代码。

        另外,为什么要使用指向字符串的指针?如果要字符串,请使用字符串;不是指向字符串的指针。很有可能,您实际上想要一个字符串。


        关于初始化列表的更多信息:

        初始化列表的用途不仅仅是初始化类的成员。它们可用于将参数传递给基本构造函数:

        class Foo
        {
        public:
            Foo(int i) { /* ... */ }
        }
        
        class Bar
            : public Foo
        {
        public:
            Bar()
            : Foo(2) // pass 2 into Foo's constructor.
                     // There is no other way of doing this.
            {
                /* ... */
            }
        };
        

        或常量成员:

        class Foo
        {
        public:
            Foo()
            : pi(3.1415f)
            {
                pi = 3.1415f; // will not work, pi is const.
            }
        private:
            const float pi;
        };
        

        或参考:

        class Foo
        {
        public:
            Foo(int& i)
            : intRef(i) // intRef refers to the i passed into this constructor
            {
                intRef = i; // does *not* set intRef to refer to i!
                            // rather, it sets i as the value of
                            // the int intRef refers to.
            }
        private:
            int &intRef;
        };
        

        【讨论】:

        • 这是一个很好的答案!还要注意,有时初始化列表是唯一的方法,因为无法分配 const 成员变量和引用……所以在这种情况下,您必须使用初始化列表。
        • 很好的答案。比我希望的要详细得多!我猜我的词汇表中缺少的词是“初始化列表”。所以现在我知道了。谢谢!
        • 现在是一个更完整的答案!
        【解决方案4】:

        你使用的语法:

        Image::Image( int width, int height, int depth ) : m_sFileName(0)  
        {  
        ...  
        }  
        

        称为初始化列表。它会将值 0 分配给您的成员变量。

        使用 m_sFileName = 0;在构造函数主体中的性能会降低,因为该成员将被初始化两次(一次是自动的,因为它不包含在初始化列表中,第二次是您的显式初始化)。

        【讨论】:

          【解决方案5】:

          与以下内容相同:

          Image::Image( int width, int height, int depth )  
          {  
              m_sFileName = 0;
           ...  
          }
          

          【讨论】:

            【解决方案6】:
            m_sFileName(0) 
            

            在构造函数的主体中将被解释为调用名为 m_sFileName 的函数。您可以将其替换为

            m_sFileName = 0;
            

            但是,推荐的初始化是在构造函数的初始化列表中,就像在第一个示例中一样。任何未在构造函数的初始化列表中初始化的数据成员都会自动使用其类型的默认构造函数进行初始化。

            【讨论】:

              【解决方案7】:

              这和做的一样

              Image::Image( int width, int height, int depth )
              {
                  m_sFileName = 0;
                  // ...
              }
              

              请注意,使用指向std::string 的指针通常不是一个好主意,因为空字符串同样是一个很好的无此处标记,如果您将其设为正常,您不必关心破坏会员。

              【讨论】:

              • 不完全一样,因为如果你做后者,你不能创建一个 const Image。在这种情况下可能不是您想做的事情,但对于更轻量级的类型可能会很有趣。
              • 如果你有一个 const 图像,你可能也想要一个 const m_sFileName,所以我看不出问题。
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-12-03
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多