2009-08-06 77 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的構造函數,而賦值將調用賦值運算符。

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