Chap 18 類別與物件 夫有土者,有大物也。有大物者,不可以物。 物而不物,故能物物。 明乎物物者之非物也,豈獨治天下百姓而已哉!

Slides:



Advertisements
Similar presentations
C++语言程序设计教程 第5章 构造数据类型 第6章 C++程序的结构.
Advertisements

Ch02物件導向程式設計 物件導向系統分析與設計.
第 2 章 初探 C++.
Memory Pool ACM Yanqing Peng.
第4章 数组 数组是由一定数目的同类元素顺序排列而成的结构类型数据 一个数组在内存占有一片连续的存储区域 数组名是存储空间的首地址
Data Abstraction: The Walls
第八章 类和对象.
走向C++之路 WindyWinter WindyWinter感谢诸位前来捧场。
struct 可以在同一個名稱下擁有多種資料型態。使用struct能讓資料的存取和處理更為靈活。
H、物件導向技術 物件導向的基本概念 物件、類別 封裝、繼承 同名異式(多型) 、超荷(過載) 物件導向分析與設計及塑模工具 UML塑模工具.
物件導向程式設計 (Object-Oriented rogramming)
4.1 概述 4.2 类与对象的实现 4.3 对象的初始化和析构 4.4 类的包含 4.5 类模板
Derived Class 前言 衍生類別的定義 單一繼承 public, protected, 和 privated 基底類別
刘胥影 东南大学计算机学院 面向对象程序设计1 2011~2012第3学期 刘胥影 东南大学计算机学院.
Scope & Lifetime 前言 Local Scope Global Functions & Objects
刘胥影 东南大学计算机学院 面向对象程序设计1 2010~2011第3学期 刘胥影 东南大学计算机学院.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
刘胥影 东南大学计算机学院 面向对象程序设计1 2011~2012第3学期 刘胥影 东南大学计算机学院.
Classes: A Deeper Look, Part 1
刘胥影 东南大学计算机学院 面向对象程序设计1 2010~2011第3学期 刘胥影 东南大学计算机学院.
Object-Oriented Programming:
類別樣板 Class Template 類似函式樣板 由類別樣板產生的類別稱為類別樣版的實體(instance)
Operator Overloading; String and Array Objects
C++语言程序设计 C++语言程序设计 第四章 数组及自定义数据类型 C++语言程序设计.
授课老师:龚涛 信息科学与技术学院 2018年3月 教材: 《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
Object-Oriented Programming in C++ 第一章 C++的初步知识
程序设计期末复习 黎金宁
第三章 C++中的C 面向对象程序设计(C++).
第12章 從C到C++語言 12-1 C++語言的基礎 12-2 C++語言的輸出與輸入 12-3 C++語言的動態記憶體配置
前處理指令可以要求前處理器 (preprocessor) 在程式編譯之前,先進行加入其它檔案的內容、文字取代以及選擇性編譯等工作。
第 6 章 函式.
2 C++ 的基本語法和使用環境 親自撰寫和執行程式是學好程式語言的不二法門。本章藉由兩個簡單的程式,介紹C++ 程式的基本結構和開發環境,讓初學者能逐漸建立使用C++ 的信心。
C++ 與 物件導向 程式設計概念簡介 魏天君 2018/12/3.
第9章 類別圖與物件圖 9-1 類別圖與物件圖的基礎 9-2 類別圖的符號 9-3 類別關係 9-4 物件圖 9-5 繪製類別圖與物件圖
第4章 物件導向分析與設計簡介 4-1 物件導向的軟體系統開發 4-2 物件導向分析與設計 4-3 UML的物件導向分析與設計
C++语言程序设计教程 第7章 类与对象 第7章 类与对象.
第九單元 Classes and data abstraction I
类类型 C++支持的内置类型和操作,如 int i=10; i=i%6; i=i+4;
C++语言程序设计 第十一章 流类库与输入/输出.
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
切換Dev c++顯示語言 工具->環境選項(V)->介面->language (Chinese TW)
Classes (2) Lecture 7.
第三章 链表 单链表 循环链表 多项式及其相加 双向链表 稀疏矩阵.
C++大学基础教程 第11章 多态性 北京科技大学 信息基础科学系 2019/4/8 北京科技大学.
第五章 递归与广义表 递归的概念 递归过程与递归工作栈 递归与回溯 广义表.
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
Oop8 function函式.
Speaker: Liu Yu-Jiun Date: 2009/5/6
Inheritance -II.
第三章 数据抽象.
Object-Oriented Programming in C++ 第二章 类和对象
<编程达人入门课程> 本节内容 为什么要使用变量? 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ:
C++大学基础教程 第10章 运算符重载 北京科技大学 2019/5/7 北京科技大学.
第 9 章 建構函式與解構函式.
授课老师:龚涛 信息科学与技术学院 2016年3月 教材:《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
第 3 章 类的基础部分 陈哲 副教授 南京航空航天大学 计算机科学与技术学院.
挑戰C++程式語言 ──第9章 函數.
#include <iostream.h>
第二章 Java基本语法 讲师:复凡.
方法進階及物件導向基礎 Lecturer: 楊昌樺.
第一讲 面向对象方法学与信息系统建模.
C++语言程序设计 C++语言程序设计 第十章 多态 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
《数据结构与算法设计》第一部分 面向对象的C++程序设计基础.
面向对象程序设计 C++教程 西安工业大学 于帆.
C++语言程序设计 C++语言程序设计 第十一章 异常处理 C++语言程序设计.
第9章 C++程序设计初步 9.1 C++的特点 9.2 最简单的C++程序 9.3 C++的输入输出 9.4 函数的重载
資料結構與C++程式設計進階 C++與資料結構 講師:林業峻 CSIE, NTU 7/ 5, 2010.
第十二章 C与C C转入C++时不需改变的内容 12.2 C转入C++的一些与类无关的 新特性
Presentation transcript:

Chap 18 類別與物件 夫有土者,有大物也。有大物者,不可以物。 物而不物,故能物物。 明乎物物者之非物也,豈獨治天下百姓而已哉! 《莊子﹒外篇 在宥第十一》 本章介紹定義類別,以及如何使用類別來定義物件的基本語法。這種使用類別和物件來設計程式的方式稱為「以物件為基礎的程式設計」(object-based programming)。

類別與物件 18.1 程式設計方法的演進 18.2 抽象化和資料的隱藏 18.3 物件與類別的關係 18.1 程式設計方法的演進 18.2 抽象化和資料的隱藏 18.3 物件與類別的關係 18.4 以物件為基礎的銀行帳戶操作程式實例 18.5 以物件為基礎的電梯操作模擬範例 18.6 朋友函數

程式設計方法的演進 函數 (function,或稱為副程式,subroutine)。 結構式程式設計 (structured programming)。 以程序為基礎的程式設計 (procedural-based programming)。 以物件為基礎的程式設計 (object-based programming)。 物件導向程式設計 (object-oriented programming,簡稱OOP)。

物件 (objects) 具有各種特質 (attributes)。 能夠展現各種行為 (behaviors)。

物件導向(object-oriented) 的程式設計 不是只重視處理問題的步驟: 在程式中保留各種物件的特性,規劃出使用者與物件,以及物件與物件間的互動關係,以完成程式資料處理的功能。 物件導向程式設計的來源: 電腦模擬 (Computer simulation) 。 Windows作業系統的誕生。

抽象化(Abstraction) 在思考問題和規劃程式的時候,先考慮: (1) 在整個系統裏面,有那些參與的物 件。 (2) 這些物件有什麼特質,能夠展現什 麼行為。 (3) 外界與物件,以及物件與物件間如 何互動。

封裝(Encapsulation) -- 資料的隱藏 物件與外界的內外區隔。 物件的特質、行為等實作的細節則被封裝在物件的內側。 通常我們可以用一個蛋的三重構造來比擬一個物件: 圖18.1.2 物件的三重構造

物件的三重構造 1. 特徵值 (attributes): 代表物件的狀態。 2. 介面 (interface): 可以和外界直接接觸。 3. 行為 (behaviors): 經由介面與外界互動而改變內部的特徵值,並把反應經由介面表現出來。

物件導向程式設計的好處 1. 提高程式的再利用率 2. 問題和程式間更直接的對應關係 區隔清楚,功能內涵,能夠發揮提綱挈領的特性。 1. 提高程式的再利用率 區隔清楚,功能內涵,能夠發揮提綱挈領的特性。 嚴謹的介面限制,避免資料和函數間不受控制的互動。 2. 問題和程式間更直接的對應關係 問題領域 (problem domain) 的每個物件,都可在程式領域 (program domain)找到相對應的物件; 可以比較直觀的進行程式規劃。 變得更有組織,更容易理解,也更易設計和除錯。

物件的特性 1. 狀態 (state)。 以一部電梯為例,它的狀態包括目前所在的樓層位置,目前的速度,要前往的目標樓層,內部乘客人數,總重,等與運作有關的細節。 2. 行為 (behavior) 。 以一部電梯為例,它的行為則有:接受按鈕呼叫,接受目的樓層選擇,以及驅動升降等功能,可以與外界互動或改變狀態。

問題領域物件與程式物件間的對應關係 成員函數又稱為方法 (methods);它能夠改變資料成員,具體的呈現物件的行為。 問題領域的物件 (Problem space objects) 軟體物件 (Software objects) 狀態(states) 行為(behaviors) 資料成員(data members) 成員函數(member functions)

訊息 (messages) 的三個要素 1.接受此訊息的物件名稱。 2.所要觸動的方法。 3.執行此方法所需要的參數。 傳送訊息相當於呼叫成員函數。

類別(class) 類別是廣義的資料型態, 是某類物件的藍圖,定義了所有這類物件擁有的資料成員和成員函數。 struct可以包括不同種類的基本資料型態,而類別 (class) 更進一步把成員函數都包裝在裏面。

int、struct和class資料型態定義的比較

public和private成員 「private:」之後的成員 (包括資料成員和成員函數) 只有同一個class內的成員函數才可以取用和呼叫。 在「public:」之後的成員開放給程式內的所有敘述。 struct除了內部成員的預設開放程度都是public以外,它和class沒有任何差異。

介面(Interface) 被設定為private的資料成員和成員函數必需透過被設定為public的函數成員才能存取。 public函數成員稱為這個class的介面。

成員函數的實作 (Implementation of member functions) 在class的本體之內實作inline成員函數 在class的本體之外實作inline成員函數 在class的本體之外實作一般的成員函數

在class的本體 (body) 之內實作inline成員函數 void CheckRate() {cout << "目前存款利率是: " << Rate << '%' << endl;}

在class的本體之外實作inline成員函數 必需在傳回資料型態之前加上關鍵字「inline」,然後在成員函數的名稱之前加上範圍確認運算子 (scope resolution operator) 「::」。例如: inline void Account::CheckBalance() { cout << "目前 " << Id << " 的帳戶餘額是 " << Balance << " 元\n"; return; }

在class的本體之外實作一般的成員函數 這個語法和inline成員函數的定義是完全一樣的,只是少了關鍵字「inline」而已。例如: void Account::WithDraw(int Cash) { Balance -= Cash; cout << Id << " 提款 " << Cash << " 元後," << "目前帳戶餘額是 " << Balance << " 元\n"; return; }

成員函數的呼叫 呼叫public成員函數是外界與物件互動的唯一方式,也是傳送訊息 (message) 給物件的方式。如圖18.3.1所示:

const成員函數 在執行時不應更動資料成員。 其語法是將關鍵字const放在參數列的括弧後面。例如: void CheckBalance() const; 它的實作部份也要改成: void Account::CheckBalance() const { cout << "目前 " << Id << " 的帳戶餘額是 " << Balance << " 元\n"; return; }

const inline成員函數 inline void Account::CheckBalance() const { cout << "目前 " << Id << " 的帳戶餘額是 " << Balance << " 元\n"; return; }

建構函數(constructor)與解構函數(destructor) 在Account類別的宣告中,有兩個成員函數非常特別,分別是: Account(); ~Account(); 它們有兩個特徵是其它成員函數所沒有的: 1. 成員函數的名稱與類別名稱相同。 2. 沒有傳回資料型態 (return data type),連void也沒有。

建構函數與解構函數 當我們進行物件的定義時,建構函數就會被呼叫。 解構函數會在物件離開它的作用範圍 (scope) 時自動被呼叫。

預設建構函數(default constructor) 由編譯器提供的預設建構函數沒有實值內容,因此沒有產生任何影響。 自己建立沒有參數的建構函數來對物件進行初始化的動作。例如: Account::Account() {Balance = 0;} 這時候,編譯器將不會再製造一個空的建構函數,由於沒有引數,它仍然稱為「預設的建構函數」。

可以接受參數的建構函數 應用C++ 允許函數重載 (overload) 的特性,可以同時建立一個可以接受參數的建構函數。例如: Account::Account(int N) {Balance = N;}

具有初始化功能的預設建構函數 (default constructor) 有兩種寫法: (1)標準成員函數的語法。例如: Account::Account() {Balance = 0;} (2)具有初始功能的縮寫語法。  建構函數名稱():資料成員名稱 (初始值) { } 例如:   Account::Account(): Balance(0) {} 如果有兩個以上的資料成員需要初始化,則可以一併完成:   Account::Account(): A1(5), A2(1){} 這兩種語法也可以在類別本體內定義。

解構函數 (destructor) 解構函數的名稱是由一個波浪符號「~」加在類別名稱之前所構成,不接受任何參數。 只有由編譯器所自動建立的解構函數才稱為「預設的解構函數」(default constructor)。 解構函數會在物件離開它的作用範圍 (scope) 時自動被呼叫。 擔任回收記憶資源的工作。 內建資料型態所定義的區域變數不需要借助解構函數,即可自動從堆疊 (stacks) 回收記憶資源。 對於陣列而言,程式設計者必需在解構函數內使用關鍵字 delete來達到這個目的。

建構函數與解構函數的自動呼叫 例如: // ... 其他敘述 { Account John; // 在區塊內定義名叫John的物件 // John.Account()在此處自動被呼叫 } // John.~Account()在此處自動 // 被呼叫

static成員 修飾詞static表示所有由這個類別所定義的物件,都共用此資料成員。 如果static資料成員遭到修改,所有的物件都會因而受到影響。 static資料成員也常被拿來累計由類別所定義的物件數目。

物件佔有的記憶體大小 由public和private資料成員的大小總和來決定。 不包括成員函數和static資料成員。

以物件為基礎的銀行帳戶操作程式範例 這個程式的功能是用來建立銀行帳戶 (account),並經由存款(deposit) 或提款 (withdraw) 來更動存款餘額 (balance)。 類別 Account與外界的互動必須透過介面Deposit()、WithDraw()、CheckBalance()、CheckRate() 和CheckCount() 來進行。 每一個實例 (instances) 的內部都有Balance,Id,Rate和Count四個特徵值,其中Rate和Count被所有實例共用,因此宣告為static變數。

以物件的觀點描述類別Account的組成和功能

標頭檔AccountClass.h 宣告類別Account,以及定義Deposit(),CheckBalance()、CheckCount() 和CheckRate() 四個inline成員函數。 此外,在這個標頭檔內設定static變數Rate和Count的初始值。 變數Rate和Count是private,因此必需透過成員函數CheckRate() 和CheckCount() 才能取用它。

範例程式 檔案 AccountClass.h // AccountClass.h #ifndef ACCOUNTCLASS_H #define ACCOUNTCLASS_H #include <iostream> #include <iomanip> using namespace::std; //---- 宣告類別 Account --------------------------- class Account { private: static float Rate; // static 變數 static int Count; // static 變數 int Balance; char Id[20];

public: Account(); // 預設建構函數 Account(char[]); // 建構函數-1 Account(char[], int); // 建構函數-2 ~Account(); // 解構函數 void Deposit (int); void WithDraw(int); void CheckBalance() const; void CheckRate () const {cout << "目前存款利率是: " << Rate << '%' << endl;} void CheckCount() const; };

} // -- 設定 static 變數初始值 --------------------- float Account::Rate = 5.8; int Account::Count = 0; // -- 定義 inline 成員函數 Deposit()-------------- inline void Account::Deposit(int CashInput) { Balance += CashInput; cout << setw(8) << Id << " 存款 " << CashInput << " 元後 " << "目前帳戶餘額是 " << Balance << " 元\n"; return; }

// -- 定義 inline 成員函數 CheckBalance()------------- inline void Account::CheckBalance() const { cout << "目前 " << setw(8) << Id << " 的帳戶餘額是 " << Balance << " 元\n"; return; } // -- 定義 inline 成員函數 CheckCount()-------------- inline void Account::CheckCount() const cout << "目前銀行共有 " << Count << " 個帳戶.\n"; #endif

檔案AccountDef.cpp 定義成員函數WithDraw(),建構函數Account(),Account(char[]),Account(char [], int),以及解構函數 ~Account()。 在建構函數和解構函數的實作內容加上了簡短的輸出訊息。 建構函數和解構函數內分別對static變數Count做遞增和遞減運算。

範例程式 檔案 AccountDef.cppp #include "AccountClass.h" #include <cstring> //-- 定義預設建構函數 Account() ------------ ----- Account::Account() { cout << "設定銀行帳戶" << endl; Balance = 0; Account::Count++; cout << "目前尚未輸入帳戶名稱.\n"; return; }

//-- 定義建構函數 Account() ---------------------- Account::Account(char Name[]) { strcpy(Id, Name); cout << "設定 " << left << setw(8) << Id << " 的銀行帳戶" << endl; Balance = 0; Account::Count++; cout << “目前 ” << setw(8) << Id << “ 帳戶餘額是 “ << Balance << " 元\n"; return; }

// -- 定義建構函數 Account() --------------------- Account::Account(char Name[], int N) { strcpy(Id, Name); cout << "設定 " << setw(8) << Id << " 的銀行帳戶" << endl; Balance = N; Account::Count++; cout << "目前 " << setw(8) << Id << " 帳戶餘額是 " << Balance << " 元\n"; return; } //-- 定義解構函數 ~Account() ------------------------- Account::~Account() cout << "徹消 " << setw(8) << Id << " 的銀行帳戶" << endl; Account::Count--; return;

// -- 定義成員函數 WithDraw() ------------------------ void Account::WithDraw(int Cash) { if (Cash > Balance) cerr << "存款不足! " << setw(8) << Id << " 這次提款不成." << endl; return; } Balance -= Cash; cout << setw(8) << Id << " 提款 " << Cash << " 元後," << "目前帳戶餘額是 " << Balance << " 元\n";

檔案AccountMain.cpp 主程式。 在不同的階段定義John、William、Cathy和Albert四個物件。 呼叫WithDraw(),CheckBalance() 和Deposit() 等成員函數以更動或顯示這些物件的存款餘額。 藉由函數sizeof() 檢查物件John的大小。 檢查static變數Count可以知道目前實例 (instances) 的存在數量。 Albert被定義在區塊內,因此它是個區域物件。

範例程式 檔案 AccountMain.cpp #include "AccountClass.h" //---------- 主程式 -------------------------------- int main() { cout << "\n(1)" << endl; // (1) Account John("John"), William("William"); // 定義兩個帳戶 Account Cathy ("Cathy", 12456); // 定義帳戶 Cathy Cathy.CheckCount(); Cathy.WithDraw(450); // 帳戶 Cathy 提款 William.Deposit(5000); // 帳戶 Cathy 存款 cout << "\n(2)" << endl; // (2) cout << "Size of John is: " << sizeof(John) << endl;

John.CheckBalance(); Cathy.CheckBalance(); William.CheckBalance(); John.WithDraw(450); cout << "\n(3)" << endl; { // (3) 區塊開始 Account Albert("Albert", 1200); // 定義帳戶 Albert Albert.CheckCount(); Albert.WithDraw(258); // 帳戶 Albert 提款 Albert.CheckBalance(); } // (3) 區塊結束 Cathy.CheckCount(); cout << "\n(4)" << endl; John.CheckRate(); return 0; }

執行結果 (1) 設定 John 的銀行帳戶 目前 John 帳戶餘額是 0 元 設定 William 的銀行帳戶 設定 Cathy 的銀行帳戶 目前 Cathy 帳戶餘額是 12456 元 目前銀行共有 3 個帳戶. Cathy 提款 450 元後,目前帳戶餘額是 12006 元 William 存款 5000 元後 目前帳戶餘額是 5000 元 (2) Size of John is: 24 目前 John 的帳戶餘額是 0 元 目前 Cathy 的帳戶餘額是 12006 元 目前 William 的帳戶餘額是 5000 元 存款不足! John 這次提款不成.

(3) 設定 Albert 的銀行帳戶 目前 Albert 帳戶餘額是 1200 元 目前銀行共有 4 個帳戶. Albert 提款 258 元後,目前帳戶餘額是 942 元 目前 Albert 的帳戶餘額是 942 元 徹消 Albert 的銀行帳戶 目前銀行共有 3 個帳戶. (4) 目前存款利率是: 5.8% 徹消 Cathy 的銀行帳戶 徹消 William 的銀行帳戶 徹消 John 的銀行帳戶

以物件為基礎的電梯操作模擬範例 電梯 (elevator) 的操作方式不外下列數種: 1. 從使用者所在的樓層呼叫電梯。 1. 從使用者所在的樓層呼叫電梯。 2. 使用者設定要前往的目標樓層。 3. 將使用者載至目標樓層。 為了簡化模擬,我們暫時忽略諸如: 1. 呼叫電梯時,有向上和向下兩種選擇。 2. 使用者可以要求電梯把門即時關上,或繼續保持開啟狀態。 3. 超重時會以聲音示警。 等細節,並且以顯示電梯目前所在位置的方式模擬電梯的運動。

以物件的觀點描述使用者和電梯間的互動

宣告類別ElevatorClass,包括: 標頭檔ElevatorClass.h 宣告類別ElevatorClass,包括:  Call(),Select() 和Move() 三個成員函數。其中Move() 是private成員函數。  建構函數Elevator() 以及解構函數 ~Elevator()。  CurrentFloor和Count兩個資料成員。其中Count是static變數

範例程式 檔案 ElevatorClass.h #ifndef ELEVATORCLASS_H #define ELEVATORCLASS_H #include <iostream> using namespace::std; //---- 宣告類別 Elevator ----------------------------class Elevator { private: int CurrentFloor; void Move(int);

public: Elevator(); // 預設建構函數 Elevator(int); // 建構函數(可設定初值) ~Elevator(); // 解構函數 void Call(int); void Select(int); static int Count; // static 變數 }; // -- 設定 static 變數初始值 ------------------------- int Elevator::Count = 0; #endif

檔案ElevatorDef.cpp 定義了建構函數Elevator(),解構函數~Elevator()以及Call(),Select() 和Move() 三個成員函數。 在private成員函數Move()的實作內容加上了簡短的輸出訊息 (例如:“燈號: 6樓”),以便模擬電梯移動時的燈號顯示。 重載的建構函數Elevator() 可以接受參數,以便設定電梯的起始位置。 建構函數和解構函數內分別對static變數Count做遞增和遞減運算,以確實掌握程式執行中物件的數量。

範例程式 檔案 ElevatorDef.cpp #include "ElevatorClass.h" Elevator::Elevator() // 定義預設建構函數 { cout << "建構函數被呼叫" << endl; CurrentFloor = 1; Count++; return; } Elevator::Elevator(int N) // 定義建構函數 (可設定初值) CurrentFloor = N; Count++; return; Elevator::~Elevator() // 定義解構函數 cout << "解構函數被呼叫" << endl; Count--; return;

void Elevator::Call(int N) // 定義成員函數 Call() { Move (N); cout << "電梯到了, 請進.\n"; return; } // ---- 定義成員函數 Select() ------------------------ void Elevator::Select(int N) cout << "載您到 " << N << " 樓.\n"; if (N > CurrentFloor) cout << "電梯向上.\n"; else cout << "電梯向下.\n"; cout << "電梯已到 " << CurrentFloor << " 樓, 謝謝光臨.\n"; return;

// ---- 定義 private成員函數 Move() ----------------- void Elevator::Move(int Target) { cout << "電梯門要關了, 請小心." << endl; int Start = CurrentFloor; cout << "電梯目前在 " << CurrentFloor << " 樓\n"; if (Target >= CurrentFloor) for (CurrentFloor = Start; CurrentFloor <= Target; CurrentFloor++) cout << " 燈號: " << CurrentFloor << " 樓\n"; CurrentFloor--; }

else { for (CurrentFloor = Start; CurrentFloor >= Target; CurrentFloor--) cout << “ 燈號: ” << CurrentFloor << “ 樓”  << endl; CurrentFloor++; } cout << "電梯門要開了, 請小心." << endl; return;

檔案ElevatorMain.cpp 主程式。 分別在兩個地方定義A和B兩部電梯,並藉由成員函數Call() 和Select() 叫用。 在程式執行當中檢查static變數Count的值,以了解目前程式內的電梯數量。

範例程式 檔案 ElevatorMain.cpp #include "ElevatorClass.h" //-------主程式------------------- int main() { // (1) cout << "(1)" << endl; Elevator A; // 定義電梯 A cout << "從 5 樓呼叫:" << endl; A.Call(5); // 呼叫電梯 A A.Select(2); // 設定電梯 A 到 2 樓 cout << "目前 Count的值是: " << A.Count << endl;

// (2) cout << "(2)" << endl; Elevator B(3); // 定義電梯 B cout << "從 4 樓呼叫:" << endl; B.Call(4); // 呼叫電梯 B B.Select(8); // 設定電梯 B 到 8 樓 cout << "目前 Count 的值是: " << B.Count << endl; return 0; }

執行結果 (1) 建構函數被呼叫 從 5 樓呼叫: 電梯門要關了, 請小心. 電梯目前在 1 樓 燈號: 1 樓 燈號: 2 樓 燈號: 3 樓 燈號: 4 樓 燈號: 5 樓 電梯門要開了, 請小心. 電梯到了, 請進.

載您到 2 樓. 電梯向下. 電梯門要關了, 請小心. 電梯目前在 5 樓 燈號: 5 樓 燈號: 4 樓 燈號: 3 樓 燈號: 2 樓 電梯門要開了, 請小心. 電梯已到 2 樓, 謝謝光臨. 目前 Count 的值是: 1

(2) 建構函數被呼叫 從 4 樓呼叫: 電梯門要關了, 請小心. 電梯目前在 3 樓 燈號: 3 樓 燈號: 4 樓 電梯門要開了, 請小心. 電梯到了, 請進. 載您到 8 樓. 電梯向上.

電梯目前在 4 樓 燈號: 4 樓 燈號: 5 樓 燈號: 6 樓 燈號: 7 樓 燈號: 8 樓 電梯門要開了, 請小心. 電梯已到 8 樓, 謝謝光臨. 目前 Count 的值是: 2 解構函數被呼叫

朋友函數 friend函數本身並非類別內的成員函數,卻被允許直接取用private成員。 函數無法自行宣告自己是某類別的friend函數,必需由類別宣告才可以。

在類別內宣告friend函數 只要在函數的宣告之前加上關鍵字friend即可。 關鍵字friend的後面沒有冒號「:」。 以模擬電梯操作的程式為例,我們可以將類別Elevator的成員函數Call() 和Select() 宣告成friend函數: friend void Call(Elevator &, int); friend void Select(Elevator &, int); private成員函數、建構函數及解構函數都不能宣告為friend函數。 在friend函數的參數列中必需要有這個物件的參照,或是物件的指標。

範例程式FEClass.h 包括friend函數宣告的完整標頭檔FEClass.h,可以拿來和ElevatorClass.h仔細比較。

範例程式 檔案 FEClass.h // FEClass.h #ifndef FECLASS_H #define FECLASS_H #include <iostream> using namespace::std; //---- 宣告類別 Elevator ---------------------------- class Elevator { friend void Call(Elevator&, int); friend void Select(Elevator&, int); public: Elevator(); // 預設建構函數 Elevator(int); // 建構函數(可設定初值) ~Elevator(); // 解構函數 static int Count; // static 變數

private: int CurrentFloor; void Move(int); }; // -- 設定 static 變數初始值 ------------------------- int Elevator::Count = 0; #endif

friend函數的定義 和一般函數的定義一樣,不需要外加類別名稱,連關鍵字「friend」也不用加。 例如friend函數Call() 的定義: void Call(Elevator& E, int N) { E.Move (N); cout << "電梯到了, 請進." << endl; return; }

範例程式FEDef.cpp 列出包括兩個friend函數Call() 和Select() 定義之完整檔案FEDef.cpp,可以拿來和ElevatorDef.cpp仔細比較。

範例程式 檔案 FEDef.cpp // FEDef.cpp #include "FEClass.h" // -- 定義 friend 函數 Call() ------------------------ void Call(Elevator& E, int N) { E.Move (N); cout << "電梯到了, 請進." << endl; return; }

// -- 定義 friend 函數 Select() ---------------------- void Select(Elevator& E, int N) { cout << "載您到 " << N << " 樓." << endl; if (N > E.CurrentFloor) cout << "電梯向上." << endl; else cout << "電梯向下." << endl; E.Move (N); cout << "電梯已到 " << E.CurrentFloor << " 樓, 謝謝光臨.\n"; return; }

// --- 定義預設建構函數 Account() -------------------- Elevator::Elevator() { cout << "建構函數被呼叫" << endl; CurrentFloor = 1; Count++; return; } // --- 定義建構函數 Account() (可設定初值) ------------ Elevator::Elevator(int N) CurrentFloor = N;

// -- 定義解構函數 ~Elevator() ----------------------- Elevator::~Elevator() { cout << "解構函數被呼叫" << endl; Count--; return; } // -- 定義 private函數 Move() ----------------------- void Elevator::Move(int Target) cout << "電梯門要關了, 請小心." << endl; int Start = CurrentFloor; cout << "電梯目前在 " << CurrentFloor << " 樓" << endl;

if (Target >= CurrentFloor) { for (CurrentFloor = Start; CurrentFloor <= Target; CurrentFloor++) cout << " 燈號: " << CurrentFloor << " 樓" << endl; CurrentFloor--; }

else { for (CurrentFloor = Start; CurrentFloor >= Target; CurrentFloor--) cout << " 燈號: " << CurrentFloor << " 樓" << endl; CurrentFloor++; } cout << "電梯門要開了, 請小心." << endl; return;

在主程式內使用friend函數 可以寫成 語法接近傳統的程序式 (procedural) 語言,卻保有「以物件為基礎的程式設計」的所有功能。 Call(A, 5); // 呼叫電梯 A Select(B, 2); // 設定電梯 A 到 2 樓 語法接近傳統的程序式 (procedural) 語言,卻保有「以物件為基礎的程式設計」的所有功能。 代價是在friend函數的定義內,每個成員都必需加上物件的名稱。

範例程式 檔案 FEMain.cpp // FEMain.cpp #include "FEClass.h" //------- 主程式 ----------------------------------- int main() { // (1) cout << "(1)" << endl; Elevator A; // 定義電梯 A cout << "從 5 樓呼叫:" << endl; Call(A, 5); // 呼叫電梯 A Select(A, 2); // 設定電梯 A到 2 樓 cout << "目前 Count的值是: " << A.Count << endl;

// (2) cout << "(2)" << endl; Elevator B(3); // 定義電梯 B cout << "從 4 樓呼叫:" << endl; Call(B, 4); // 呼叫電梯 B Select(B, 8); // 設定電梯 B 到 8 樓 cout << "目前 Count 的值是: " << B.Count << endl; return 0; }