2013-10-08 85 views
1

這是一個從http://www.learncpp.com/cpp-tutorial/92-overloading-the-arithmetic-operators/爲什麼我需要在有私有變量時使引用保持不變?

代碼的位我一直在調查運營商從幾個自我教育網站和瀏覽論壇重載。我問了一個關於使用不同方法重載的問題,現在我明白了。那Q &鏈接在這裏How is this returning a value when it has not been defined?

但是,這種方法引用我不明白。我試圖用不同的方式來實現代碼,並且看到了一些不那麼複雜的工作方式。

我知道做到這一點的方法是使一個類的實例作爲操作功能,操作函數的臨時實例的參數,與=運算符返回的值。這種方式要複雜得多,我爲此甚至需要解決一些問題。因爲你去的代碼,但這裏有三個問題我有

這些問題的措辭。
(問題1)Ceteris parabis,爲什麼我需要參數中的const關鍵字?我知道,如果我公開變量,我不知道,但爲什麼如果有一個朋友類,或者如果代碼寫入類本身,我需要使用const。
(問題2)如果我將朋友功能放在課堂內,我仍然需要關鍵字「朋友」爲什麼?
(問題3)初始化類別c1和c2在哪裏?他們有一個參考,但在返回之前沒有初始化,但是低於參考。我認爲編譯時會出現錯誤。

class Cents 
{ 
private: 
    int m_nCents; 

public: 
    Cents(int nCents) { m_nCents = nCents; } 
    //I know this assigns each 
    //instance to the private variable m_nCents since it's private. 

    // Add Cents + Cents 
    friend Cents operator+(const Cents &c1, const Cents &c2); 

    //why do we need 
    //to make this a friend? why can't we just put it inside the class and not 
    //use the "friend" keyword? also why do I need to make the variables public 
    //if i remove const from the parameters 

    int GetCents() { return m_nCents; } 
    //I know how this is used to return the 
    // variable stored in m_nCents, in this program it is for cout 
}; 

// note: this function is not a member function! 
Cents operator+(const Cents &c1, const Cents &c2) 
//where are these references 
//actually defined? I do not see c1 or c2 anywhere except in the return, but 
//that is below the code that is referencing the class 
{ 
    // use the Cents constructor and operator+(int, int) 
    return Cents(c1.m_nCents + c2.m_nCents); 
} 

int main() 
{ 
    Cents cCents1(6); 
    Cents cCents2(8); 
    Cents cCentsSum = cCents1 + cCents2; 
    std::cout << "I have " << cCentsSum .GetCents() << " cents." << std::endl; 

    return 0; 
} 

回答

4

也許下面是更能說明問題:當你計算的總和,你的代碼就相當於:

Cents cCentsSum = operator+(cCents1,cCents2); 

(是的,上面是實際的法律代碼以及)。

這更像是一個函數調用,它實際上是操作符。參考文獻是參數,因此const Cents& c1參考文獻cCents1const Cents& c2參考文獻cCents2

這個免費功能現在需要實現,但您正在訪問c1.m_cents,這是private。爲了做到這一點,你需要聲明方法friend,否則你寫的自由函數會產生訪問錯誤。

仍然即使你把它放在類裏面,因爲操作符是特殊的,所以需要聲明它爲friend。編譯器看到你的運營商+有兩個的論點,因此它知道這是而不是的一個成員函數。它實際上相當於免費函數的代碼,只是更緊湊。

最後,您希望那些引用是const以避免意外修改。試想,如果你寫:

Cents operator+(Cents &c1, Cents &c2) 
{ 
    return Cents(c1.m_nCents += c2.m_nCents); 
} 

注意+=,而不是+,它會修改c1值。在你的榜樣,這將意味着你叫

Cents cCentsSum = cCents1+cCents2; 

cCents1價值將被修改。當然不可取。通過設置參數const引用,可以讓編譯器確保上述操作不會發生,並在編譯代碼時報告爲錯誤。

+0

這是非常簡單和有益的。我現在理解問題3。對於問題1,我瞭解const的重要性,但是當我刪除const關鍵字時,我的編譯器XCode會拋出所有其他東西保持不變的錯誤。那是因爲我的編譯器知道結果可能是災難性的,所以它決定不編譯它,或者這會導致任何編譯器錯誤? – Scott

+0

@Scott您是否已經爲'friend'聲明*和*實際定義刪除了'const'?他們需要匹配,你不能刪除其中的一個'const'。 –

+0

@Scott我在回答中增加了一段,希望能幫助你理解Q2。 –

3

大獎金爲const是不是就意味着他們不會改變,因爲C++編譯器可以看到所有的類型,如果不是可變的,但常量它知道,只有const的方法可以被調用,這樣,廣告它可以強制const方法不會改變該狀態(當編譯這些類的實現時)

當你使用const任何東西時,編譯器可以確定它不會改變(除非mutable,儘管忽略它),所以它可以對代碼進行一些漂亮的優化。

如果每個函數參數都是const並且不可變,那麼編譯器知道它何時使用那些函數使得對象在調用之前和之後處於相同的狀態,因此寄存器中的任何值都不需要刷新(儘管寄存器分配來得晚得多)。

Const爲好,如果有人是「總常量妓女」這是一種恭維。

因此,要回答這個問題,只有朋友和類可以改變國家的私人手段,常量意味着沒有人能(除非可變)。

這很難,因爲當編譯器可以證明,按照/標準所產生的代碼放在雖然完全相同的程序狀態,如果它做你寫的優化僅發生來舉個例子。

class State { 
private: 
    bool state; 
public: 
    State() { 
     state = false; 
    } 
    bool getState() { 
     return state; 
    } 
    void alterState() { 
     state = !state; 
    } 
}; 

void doSomething(State&); 

int main(int,char**) { 
    State state; 
    bool before = state.getState(); 
    std::cout<<"The state is: "<<before<<"\n"; 
    doSomething(state); 
    bool after = state.getState(); 
    std::cout<<"The state is: "<<after<<"\n"; 
    return 0; 
} 

假設doSomething是在另一個文件中定義的。

當我們發現後,編譯器必須做state.getState()的調用,因爲它不能證明前==後。

然而,如果我們有:

void doSomething(const State&); 

int main(int,char**) { 
    State state; 
    bool before = state.getState(); 
    std::cout<<"The state is: "<<before<<"\n"; 
    doSomething(state); 
    bool after = state.getState(); 
    /*compiler can do after=before because bool 
    is a type that will produce the same result 
     as if it actually did the getState*/ 
    std::cout<<"The state is: "<<after<<"\n"; 
    return 0; 
} 

這說明常量是如何偉大。編譯器知道doSomething需要一個常量(引用一個)狀態,並且由於狀態沒有可變字段,它知道狀態狀態無法因該調用而改變。如果他們都在同一個文件中,它可能會看到什麼做什麼(它不會改變狀態),並意識到它可以做到這一點,現代的非常聰明。你想給編譯器一個優化的機會。

傳遞const引用意味着所有內容都可以看起來不觸及,所以編譯器必須處理的任何值都是有效的,因爲它是常量,它們不能更改。

記住這一點: 所有的優化工作就好像它們從未發生過一樣,程序狀態是一樣的,沒有秒錶或調試器或反彙編器,你不能說出編譯器做了什麼。它可以優化一些變量(如果它可以證明沒有副作用),打印該變量雖然會阻止它這樣做,但編譯器將按照標準始終按照您輸入的內容進行操作。

+0

令人驚歎的解釋爲什麼編譯器需要const關鍵字。至於朋友類,如果我將該類中的函數移動到該類中,那麼爲什麼仍然需要在變量爲私有時包含該朋友詞?是否因爲裏面有引用在類之外初始化? – Scott

+0

@Scott不太清楚這意味着什麼,如果你將一個函數複製並粘貼到一個類聲明中,它就成爲一個成員....你不應該需要這個,去你的問題點擊編輯放置「__bonus round__」使它大膽,並在那裏舉一個例子或問題(在沒有工作的情況下,使大膽的東西在它之前和之後放兩個下劃線) –

相關問題