C++ 方法声明问题

发布于 2024-07-30 11:19:34 字数 465 浏览 6 评论 0原文

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

I have some code in 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;  
};  

My question is: what is happening with m_sFilename in the first line? I guess it is set to NULL but what's the point of doing it that way. Would it be the same to do:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

岁吢 2024-08-06 11:19:35

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

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

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;
};

The first uses what's called an initialization list.

When you enter the body of the constructor, all of the classes members must have been constructed (so they can be used). So if you have this:

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

So, str gets constructed, then assigned. Better would have been:

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

So that str gets directly constructed. This does not make a difference in your case because pointers have no constructor.

It is generally considered good practice to use an initialization list over running code in the constructor. The initialization list should be used for initializing, the constructor should be used for running code.

Also, why use a pointer to string? If you want a string, use a string; not a pointer to string. Chances are, you actually want a string.


More about initializer lists:

Initializer lists have more uses than just initializing members of the class. They can be used to pass arguments into base constructors:

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.
    {
        /* ... */
    }
};

Or constant members:

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

Or references:

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;
};
变身佩奇 2024-08-06 11:19:35

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

This is called an initializer. You should get used to using them. In this case it doesn't matter. But in other cases not using them could mean a double initialization of a non-pointer-member. First with the default values, then with your values.
And finally there is the case of a member without a constructor without parameters. In those cases you have no choice but using an initializer.

鱼忆七猫命九 2024-08-06 11:19:35

这与执行相同

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

请注意,使用指向 std::string 的指针通常不是一个好主意,因为空字符串是一个同样好的 Nothing-here-marker,并且您不这样做如果你让它成为普通会员,就必须关心破坏。

It would be the same as doing

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

Please note that using a pointer to a std::string is usually not a good idea, as an empty string is an equally good nothing-here-marker and you do not have to care about the destruction if you make it a normal member.

狂之美人 2024-08-06 11:19:35
m_sFileName(0) 

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

m_sFileName = 0;

但是,建议的初始化位于构造函数的初始化列表中,如第一个示例所示。 任何未在构造函数的初始化列表中初始化的数据成员都将使用其类型的默认构造函数自动初始化。

m_sFileName(0) 

in the constructor's body will be interpreted as calling a function with the name m_sFileName. You could replace it with

m_sFileName = 0;

However, the recommended initialization is in the initialization list of the constructor, like in the first example. Any data member that is not initialized in the initialization list of the constructor will be automatically initialized with the default constructor of its type.

忆离笙 2024-08-06 11:19:35

它的作用与以下相同:

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

It does the same as:

Image::Image( int width, int height, int depth )  
{  
    m_sFileName = 0;
 ...  
}
浴红衣 2024-08-06 11:19:35

您正在使用的语法:

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

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

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

The syntax you are using:

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

is called an initialization list. It will assign the value 0 to your member variable.

Using m_sFileName = 0; in the constructor body would be less performant because the member would be initialized twice (one time automatically because it is not included in the initialization list, and a second time with your explicit initialization).

笑看君怀她人 2024-08-06 11:19:35

这两个变体几乎相同——您是正确的,这

: m_sFileName(0)

导致m_sFileName被初始化为0

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

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

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

Those two variants are almost the same -- you're correct that the

: m_sFileName(0)

is causing m_sFileName to be initialized to 0.

The reason why C++ has this special initialization syntax becomes important when you want to create a const Image. (Probably not something you want to do in this case, but it can something you might want to do for "lightweight" types.) For a const Image, this is a const pointer in the constructor as well as in every "normal" member function, and so m_sFileName=0 is not allowed.

To solve this problem, C++ has initialization lists, which perform initialization, not assignment. Incidentally, if m_sFileName were an object, there would be an additional difference besides the const considerations: The initialization list would cause m_sFileName's constructor to be called, whereas the assignment would call the assignment operator.

Apart from all of these considerations, initialization lists are a good way to communicate intent -- to signify that you're initializing, not assigning.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文