2015-11-06 71 views
0

我有兩個類之間的朋友函數的問題。讓我們來看看一些代碼:朋友函數和包含循環

第一類:

#ifndef _FIRST_H_ 
#define _FIRST_H_ 

//#include "Second.h" 
#include <string> 

class Second; 
class First 
{ 
    friend void Second::fun(); 

    std::string str = "Dziala\n"; 
public: 
    First(); 
    ~First(); 
}; 
#endif 

,二類:

#ifndef _SECOND_H_ 
#define _SECOND_H_ 

#include<iostream> 
#include "First.h" 

class Second 
{ 
    First fObj; 
public: 
    Second(); 
    ~Second(); 
    void fun() { std::cout << fObj.str; } 
}; 
#endif 

是沒有問題的,如果我試圖讓友元類。如果我像上例中的朋友FUNCTION一樣發生問題。 我可以通過#include「Second.h」在First class中解決這個問題,但它會包含循環。你有什麼想法如何做到這一點?

+0

'#include'循環沒有問題,不是當你用'#ifndef _FIRST_H_' –

+3

@MadsMarquart啓動它們時,不是這樣。這將是一個問題。 –

+0

另外,我不明白你爲什麼想要這樣做?檢索字符串似乎很沒用。 –

回答

0

你有什麼想法如何做到這一點?

你不能使用friend機制來做你正在嘗試的。

一個簡單的解決方案是通過成員函數公開First::str,而不用擔心friend結構。這是一個更清晰的解決方案。

class First 
{ 
    public: 
    First(); 
    ~First(); 

    std::string const& getString() const { return str; } 

    private: 
    std::string str = "Dziala\n"; 
}; 
+0

爲什麼?如果我可以使用朋友CLASS,那麼爲什麼我不能使用朋友FUNCTION機制? – QueUe

+1

@QueUe,根據我的經驗,使用「朋友」機制是最後的選擇 - 無論你是上課還是作爲「朋友」。這是類間緊密耦合的症狀。通過讓'Second'成爲'First'的朋友,你已經使'Second'與'First'的內部緊密結合了。 'First'不能在沒有諮詢'Second'的情況下自由地改變它的內部。 –

+0

不幸的是,這是我編程課程的作業。我必須使用朋友功能:) – QueUe

1

問題occures如果我交朋友的功能就像在上面的例子。

// #include "Second.h" 
#include <string> 

class Second; 
class First 
{ 
    friend void Second::fun(); 
... 

的第一行是Second類的聲明。這是一個前向聲明。對於Second類,在聲明之後並且在其定義出現之前,它是不完整類型。所以Second被稱爲類類型,但其中包含的成員未知。所以你不能在這裏使用會員void Second::fun()

friend class Second工作正常,因爲它從來不嘗試使用不完整類型的成員。

但是它會包括循環。

正如MadsMarquart所說,這不是一個問題,因爲你已經有了頭衛隊。

任何想法如何做到這一點?

如果您想使用friend void Second::fun()作爲朋友聲明,聲明和定義的順序很重要,並且需要對您的類進行一些修改。

  1. 申報類First
  2. 定義類別Second聲明(未定義)fun()
    • 您不能使用First fObj作爲成員或嘗試new First現在,因爲First沒有定義和First構造,現在還是個未知數。 A 指針或參考會沒事的。
    • 由於使用了指針或引用,因此也應修改**構造函數。
  3. 定義類別First與朋友聲明fun()
  4. 定義fun()

代碼對你的例子,改裝基地,

class First; 

class Second { 
public: 
    Second(First& rfObj) : fObj(rfObj) {} 
    void fun(); 

private: 
    First& fObj; 
}; 

class First { 
    friend void Second::fun(); 
public: 
    First() = default; 

private: 
    std::string str = "Dziala\n"; 
}; 

void Second::fun() { std::cout << fObj.str; } 
0

這是不可能的聲明一個成員函數作爲一個朋友,除非完整的類定義可見。否則允許任意代碼聲明和定義該類的創建者不打算的類的成員。

class Second  // complete class definition, not just a forward declaration 
{ 
    public: 

     void fun(); 
}; 

class First 
{ 
    friend void Second::fun(); 
}; 

這樣做的結果是,First不能簡單地是Second成員。爲了接受這一點,編譯器需要知道Second的完整定義,以便編譯First的定義,但也需要知道要編譯的Second定義的完整定義First。這是一種無限遞歸的依賴關係,這往往會打亂編譯器。

只有前向聲明才能聲明的類成員(或實際變量)的唯一類型是指針或引用。

所以,這將工作

class First; 

class Second  // complete class definition, not just a forward declaration 
{ 
    private: 
     First &fObj; // note this is a reference 
    public: 

     void fun(); 

     Second(); 
     ~Second(); 
}; 

class First 
{ 
    friend void Second::fun(); 
}; 

Second::Second() : fObj(*(new First)) // assumes First has appropriate (not shown) constructor 
{} 

Second::~Second() 
{ 
    delete &fObj; 
} 

但是,請注意,無論是構造和Second也析構函數不能編譯,除非First的定義是編譯器事前可見。這是因爲無法僅基於前向聲明(即與原始問題相同的原因)創建或銷燬類類型的實例。

實際上,我只是宣佈類SecondFirst的朋友,並且完成它。畢竟,將類的一個成員函數聲明爲朋友聲明,成員函數將始終按照預期工作。在極少數情況下,可以相信一個類的單個成員函數按照需要工作,但不相信同一類的其他成員函數。

+0

它出現了一系列的編輯提議,並在過去的24小時內被其他成員拒絕我的回答。我最後的編輯實際上是由Chao Mai提出的,旨在糾正一些錯誤,因爲出於某種原因,我沒有權力接受(如我所願)或拒絕他們。 – Peter