追蹤

宗宗大學

喜歡關注科學、哲學、社會、政治、教育,未來想當一位抱著理想的科學家,期許社會能夠進步。

[筆記]夥伴函式與類別、不夠朋友問題|C++


夥伴函式和成員函式差在哪裡?為什麼輸入/輸出的多載運算子一定要為夥伴函式?如果A類別把B函式當作夥伴,但B函式的參數中沒有A類別,顯然這個B不把A當夥伴,這會造成main()無法找到B函式。

還是很困惑嗎?文章裡有答案喔~😎

一、夥伴 (friend)

(一)函式

雖然friend函式的函式原型宣告在類別中,但它不是成員函式。如果介面和實作是合在一起的話,friend函式是定義在類別外面;而如果介面和實作分開,成員函式必須加上範圍解析子::,但非成員函式不需要,這也包含friend函式。

也就是friend函式的定義是獨立於類別的,並且如果friend函式想要獲得public資料成員的存取權,friend函式不能主動設定,並需類別主動給予friend函式權限。

有些不支持friend函式的原因,覺得friend的機制會破壞OOP的基本原則。

(二)多載函式 (overloading)

1. 輸入輸出

<<, >> 多載時,一定要宣告成friend,因為我們不能動ostream物件的東西,故只能授權ostream能存取新物件的private成員。且傳參考給運算子,也回傳參考(lvalue),這樣就可以連續輸入/輸出,不可以回傳區域參考,不然會消失!這點和指標一樣~

2. 多載成員函式 v.s. 多載夥伴函式

  1. cost + tax
  2. cost.operator+(tax) //member function, cost must be an object,使用上比較沒有彈性
  3. operator+(cost, tax) // non-member function,使用上比較有彈性

(三)類別 (class)

friend類別和friend函式一樣,給予protected, private權限給他。friend類別除了要在類別定義中放上friend類別原型外,如果夥伴類別和授與權限的類別是在不同的檔案中,夥伴類別須向前宣告(forward declaration),不需要#include。例如:stackNode和stack關係非常緊密,

範例:stackNode和stack

// stackNode.h

class Stack; // Forward declarartion

 

class StackNode {

    friend class Stack; // Make stack a friend

public:

    ...

    

private:

    int data;

    StackNode *nextPtr;

};

// stack.h

#include "stackNode.h"

 

class Stack{

public:

    ...

    

private:

    StackNode *firstPtr;

    StackNode *lastPtr;

};

夥伴的授與是主動的,不能被動授與。因此如果stack想要拿到stackNode的權限,必須stackNode主動授與。要注意的是夥伴關係依舊不是類別的成員關係,因此夥伴函式/類別 (stack)需間接使用授與類別 (stackNode)的成員。也就是stack須先實例化stackNode,再透過stackNode物件去存取其中的protected, private成員。

(四)不夠朋友問題

在作業3當中,會遇到不夠朋友問題。以下程式碼為Complex類別中,宣告friend函式Polar(),可以看到參數列並沒有使用到Complex物件,這就會發生不夠朋友問題。

friend Complex Polar(const double leng, const double arg);

使用在類別中的friend函式時,如果friend函式的參數沒有使用類別本身,則main()就無法偵測到此friend函式,但如果friend函式參數有使用到類別本身,main()就可以偵測到此friend函式。其解決方法:

  1. 可以在.hpp的class外再宣告一次函式
  2. 或是在main.cpp中在宣告一次函式,這樣main()就可以被找到。
  3. 或是傳給Polar一個Complex的參數,這樣也可以。

這就像是我跟你是朋友,但你卻沒有使用到我(傳入的參數),我就不跟你好的概念,C++也是蠻講義氣的(X)。

更多此問題的討論

(五)實作細節

作業3實作上需要注意一些細節

  1. 因為friend function不是member function,所以沒有this指標,故必須傳Complex& x給函數,因為x要更改,所以不能宣告成const
  2. 因為+號已經overloading,所以直接使用x + y即可。不過因為x要更改,所以不能直接return x + y;,必須先更新x再回傳x。

// Overloading +=

Complex operator+=(Complex& x, const Complex& y){

    x = x + y;

    return x;

}

  1. 如果不使用已經多載的+號,則必須先複製出一個xCopy,再更新x的值。不然直接更新x.real後,x.imag的更新會出問題。+=直接更新可能沒問題,但*=會出錯。

// Overloading +=

Complex operator+=(Complex& x, const Complex& y){

    const Complex xCopy = x;

    x.real = xCopy.real + y.real;

    x.imag = xCopy.imag + y.imag;

    return x;

}

更多作業細節,請參考AOOP Homework source code

二、相關文章

  1. 物件導向程式設計|模擬真實世界的方式|江明朝
  2. AOOP Homework source code
  3. [筆記]109-2高等物件導向程式設計 期中考
  4. [筆記]介面與實作、運算子多載、左值右值、參數傳遞、回傳多值|C++
  5. [筆記]陣列與指標|C++
  6. [筆記]類別、特殊函式、內嵌函式、函式物件|C++
  7. [筆記]繼承模式與存取權限|C++
  8. [筆記]多型與繼承的關係|C++
  9. [筆記]static / const成員資料與函式|C++
  10. [筆記]夥伴函式與類別、不夠朋友問題|C++

 


本文章發表於:課程

加入85

宗宗大學

國立中山大學 生物科學系

追蹤 384 鼓勵作者

喜歡關注科學、哲學、社會、政治、教育,未來想當一位抱著理想的科學家,期許社會能夠進步。

鼓勵作者

目前持有 Blink Coin: Loading..

選擇禮物


愛心

(Coin 10)

幫高調

(Coin 20)

咖啡

(Coin 30)

掌聲鼓勵

(Coin 40)

崇拜眼神

(Coin 50)

驚呆了

(Coin 60)

神人4ni

(Coin 70)

花束

(Coin 100)

鑽石

(Coin 300)

紅寶石

(Coin 500)

藍寶石

(Coin 1000)

黃寶石

(Coin 3000)


送出鼓勵



發表匿名文章不會出現你的大頭圖與名稱,你可暢所欲言,但文章內容務必遵守「佈告欄使用規範」!


回應

送出回應


想回應這篇文章嗎?也想發表文章嗎?
馬上登入來發表文章、追蹤作者、收藏文章或回應文章吧!

註冊 登入