2009-08-06 75 views
4

我有一些代码在Image.cpp:C++方法声明的问题

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

我的问题是:什么是在第一线与​​发生了什么?我想它被设置为NULL,但这样做的重点是什么。会是相同的事:

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

回答

0

这将是一样的做

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

请注意,使用一个指向std::string通常不是一个好主意,因为一个空字符串一个同样好的无所不在的标记,如果你把它变成一个普通的成员,你不必关心破坏。

+0

这不完全相同,因为如果你做后者,你不能创建一个常量图像。在这种情况下可能不是你想要做的事情,但对于更轻量级的类型可能有意思。 – 2009-08-06 07:29:22

+0

如果你有一个const图像,你可能也需要一个const m_sFileName,所以我没有看到问题。 – MSalters 2009-08-06 07:53:24

0
m_sFileName(0) 

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

m_sFileName = 0; 

取代它。然而,推荐初始化是在构造函数初始化列表,如在第一个例子。任何未在构造函数的初始化列表中初始化的数据成员都将使用其类型的默认构造函数自动初始化。

0

它确实一样:

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

你们很快... – Lucas 2009-08-06 07:27:20

11

第一种使用所谓的一个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; 
}; 
+2

这是一个很好的答案!还要注意,有时初始化列表是唯一的方法,因为不能分配const成员变量和引用......所以在这种情况下,你必须使用初始化列表。 – 2009-08-06 07:32:13

+0

嘿,你在编辑时输入了评论。 :) – GManNickG 2009-08-06 07:33:58

+0

很好的答案。比我希望的更多的细节!我想我的词汇中缺少的单词是“初始化列表”。所以现在我知道了。 Thankx! – 2009-08-06 07:49:02

2

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

0

你正在使用的语法:

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

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

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

0

这两个变体几乎是相同的 - 你是正确的,因为

: m_sFileName(0) 

导致m_sFileName被初始化为0

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

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

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