4

我在 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);  
...  
}
4

7 回答 7

11

第一个使用所谓的初始化列表

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

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;
};
于 2009-08-06T07:27:37.807 回答
2

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

于 2009-08-06T07:28:10.647 回答
0

这和做的一样

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

请注意,使用指向 a 的指针std::string通常不是一个好主意,因为空字符串同样是一个很好的 nothing-here-marker,如果将其设为普通成员,则不必关心破坏。

于 2009-08-06T07:22:43.247 回答
0
m_sFileName(0) 

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

m_sFileName = 0;

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

于 2009-08-06T07:23:37.987 回答
0

它与以下内容相同:

Image::Image( int width, int height, int depth )  
{  
    m_sFileName = 0;
 ...  
}
于 2009-08-06T07:25:47.813 回答
0

您正在使用的语法:

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

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

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

于 2009-08-06T07:30:33.277 回答
0

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

: m_sFileName(0)

导致m_sFileName被初始化为0.

当您想要创建一个const Image. (在这种情况下可能不是您想要做的事情,但它可以是您可能想要为“轻量级”类型做的事情。)对于 a const Imagethis是构造函数以及每个“普通”成员函数中的 const 指针,并且所以m_sFileName=0是不允许的。

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

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

于 2009-08-06T07:35:17.637 回答