C++ How to Program 7/E 筆記
第三章 類別與物件簡介
學習目標
|
|
GradeBook 類別的UML類別示意圖
在UML中,妹個類別都會在UML類別示意圖(UML class diagram)中以一個長方形代表,裡面有三個部分。
中間空,的表示GradeBook 類別沒有任何屬性。
第三行「+」表示displayMessage是一種UML公用(public)型的操作。(即C++的public 成員函式)
()是用來建立操作模型。在此範例中displayMessage無需額外資料便可執行工作。
定義一個具有「參數」的成員函式
參數(parameter) 可提供成員函式在執行工作所需要的額外資訊。
就如同汽車需要加速,參數即是在幫助汽車決定加速程度。
呼叫函式時,呼叫者會提供每個參數的「值」——>即引數(Argument)
圖解
此時的GradeBook 類別的UML 類別示意圖
資料成員、set 函式與 get函式
我們將程式的所有辨識都宣告在main函式中,在函式定義主體中宣告的變數,就稱為區域變數(local variable)。區域變數要先宣告,才能在函式中使用。而在這個該函數之外的地方皆無法存取這個變數。(當然有例外)
類別通常由一或多個成員函式組成,這些函式可操控特定物件的屬性。
屬性由類別定義中的變數表示,這種變數稱作資料成員(data member)。資料成員會在類別定義中宣告,但他的宣告在成員函式定義主體的外部。
在下方範例中Gradebook類別將課程名稱當作資料成員,因此可在程式中隨時使用或修改它。
原則上,資料成員應宣告為private,成員函式應宣告為public。
雖然public 和private存取修飾子可以重複交錯,但最好統一羅列。
用存取修飾子private宣告資料成員稱作資料隱藏(data hiding)。當成是建立(實體化)一個 GradeBook 物件時,此物件就封裝(隱藏)了資料成員courseName,只有該類別的成員函式能存取他。
含一個資料成員、一個set 函式與get函式的GradeBook UML類別示意圖
courseName 屬性的UML型別是String,對應到 C++ 的 string。資料成員courseName 在C++中是 private,所以類別示意圖在屬性名稱前面加上減號 (-)。
- setCourseName 操作有一個String型別的參數,叫做name。
- getCourseName在C++中的傳回型別是String,因此在()之後以「:string」表示。
- setCourseName、displayMessage不會傳回任何值(傳回void),故()後方為空。
以建構子將物件初始化
在前面的範例中,建立GradeBook 物件時,資料成員courseName 會預設初始化為空字串。若在建立時,想同時提供課程名稱呢?
⇒⇒所宣告的每個類別都可提供建構子(constructor)
*建構子是一種特殊的成員函式,名稱必須和類別相同,編譯器才能區別他與其他成員函式。建構子與其他成員函式的一個重要差異,就是建構子不能還回數值,因此他不能指定傳回型別(就連void也不行)。通常,建構子都宣告為public。
C++建立每個物件都要呼叫建構子,以確保程式使用物件前,每個物件均已初始化。建立物件時,就隱含了建構子的呼叫。
若類別沒有明確寫出建構子,編譯器就提供一個預設建構子(default constructor),也就是沒有參數的建構子。
*為類別提供預設建構子的兩種方式
沒有參數的建構子就叫預設建構子。預設建構子的建立方式有兩種:
- 若類別沒有定義建構子,編譯器就會自行為他建立一個預設建構子。為初始化的變數通常會包含一個「垃圾值」(garbage value)
- 由你明確定義一個沒有參數的建構子。這種預設建構子可執行你指定的初始化動作,若資料成員本身是類別物件,也會呼叫每個資料成員的預設建構子。
將建構子納入GradeBook 類別的UML類別示意圖
在此GradeBook 類別模型,他有一個建構子,其參數名稱是name,型別是string。
為了區分建構子和類別操作,UML在建構子名稱前面會加上
<<contructor>>。習慣上會將建構子放在其他操作前面。
✯✯✯ 將類別放在獨立檔案以提高重複使用性
建立類別定義的好處在於,若套件設定得當,程式設計者便可重複使用我們的類別。但是若有其他程序員想要使用GradeBook類別,得注意到不能全部照抄,否則會因為有兩個main韓式,而讓程序錯誤。
在Microsoft Visual C++編譯會產生以下錯誤:
error C2084: fucntion ‘int main(void)’ already has a body
而在GNU C++編譯器會產生如下錯誤
redefinition of ‘int main()’
標頭檔
前面的程式皆為副檔名 (.cpp),此檔稱作原始碼檔案(source-code file)包含GradeBook 類別定義和一個main函式。
在建構物件導向C++程式時,通常會將可再利用的原始碼定義在副檔名為(.h)的檔案中,這就是標頭檔(header file)。程式使用#include箝制處理指令已函入標頭檔,藉此運用可再利用的軟體元件。
如何找到標頭檔
GradeBook.cpp檔案中,第四行檔名是以雙引號 (“ ”)包覆而非(< >)。程式原始碼檔案與使用者自定標頭檔通常會放在相同目錄下,當前置處理器碰到雙引號的標頭檔名時,會再與# include指令出現的檔案相同目錄中尋找標頭檔。若遇到的是<>的標頭檔時,會假設該逼頭飾C++標準函式庫的一部份,而不會尋找被前置處理的程式所在目錄。
將介面與實作分開
軟體工程基本守則——將介面與實作分開(separating interface from implementation)
類別介面(interface of a class)說明類別提供了「什麼」服務給用戶端以及如何要求這些服務,但沒有說明「如何」實作這些服務。類別介面由類別的public 成員函式組成。
注意,每個函式標頭的成員函式名稱前面堆有類別名稱和::,這叫做二元使用域解析運算子(binary scope resolution operator)。他們會把每個成員函式綁到宣告成員函式與資料成員的GradeBook 類別定義上面
若不在函式前面加上「GradeBook :: 」,則編譯器就不知道這些函式是GradeBook 類別的成員函式,會把他們當成全域函式。(page3-31)
注意,每個函式標頭的成員函式名稱前面堆有類別名稱和::,這叫做二元使用域解析運算子(binary scope resolution operator)。他們會把每個成員函式綁到宣告成員函式與資料成員的GradeBook 類別定義上面
若不在函式前面加上「GradeBook :: 」,則編譯器就不知道這些函式是GradeBook 類別的成員函式,會把他們當成全域函式。(page3-31)
在程式裡,我們習慣將類別定義與使用該類別的用戶端程式碼分開,而為了不要讓類別定義中的成員函式實作被修改,進而影響到用戶端程式碼的失靈,因此在編寫程式時,會將類別定義在被分割成成:類別介面和類別實作。此時類別實作會被隱藏起來僅留下類別介面。
jjj
附錄:語法
GradeBook with “Welcome to the Grade Book!”
//
//Define class Gradebook with a member function displayMessage.
// create a GradeBook object, and call its displayMessage function.
#inclued <iostream>
using namespace std;
// GradeBook calss definition
class GradeBook
{
public:
//function that displays a welcome message to the GradeBook user
void displayMessage()
{
cout << " Welcome to the Grade Book!" << endl;
} //end function displayMessage
};// end class Gradebook
//function main begins program execution
int main()
{
GradeBook myGradeBook; // create a GradeBook object named myGradeBook
myGradeBook.displayMessage(); // call objet's displayMessage function
}
|
GradeBook add “couseName”
//
// Define class GradeBook with a member function that takes a parameter;
// Create a GradeBook object and call its displayMessage function.
# include <iostream>
# include <string> // program uses C++ standard string class
using namespace std;
// GradeBook calss definition
class GradeBook
{
public:
// function that displays a welcome message to the GradeBook user
void displayMessage (string courseName)
{
cout << "Welcome to the grade book for\n" << courseName << "!"
<< endl;
} // end function displayMessage
}; // end class GradeBook
//function main begins program execution
int main()
{
string nameOfCourse; // string of characters to store the course name
GradeBook myGradeBook; // create a GradeBook object named myGradeBook
// prompt for and input course name
cout << "Please enter the course name:" << endl;
getline( cin, nameOfCourse ); // read a course name with blanks
cout << endl; // out put a blank line
// call myGradeBook's displayMessage function
// and pass nameOfCourse as an argument
myGradeBook.displayMessage( nameOfCourse );
} // end main
|
資料成員、set、get
//
// define class GradeBook that contains a courseName data member
// and member functions to set and get its value;
// Create and manipulate a GradeBook object with these functions.
# include <iostream>
# include <string>
using namespace std;
//GradeBook class definition
class GradeBook
{
public:
// function that sets the course name
void setCourseName (string name)
{
courseName =name;//store the course name in the project
} // end function setCourseName
// function that gets the course name
string getCourseName()
{
return courseName; // return the object's courseName
}// end function getCourseName
// fucntion that displays a welcome message
void displayMessage()
{
// this statement callls getCourseName to get the
// name of the course this GradeBook represents
cout << "Welcome to the grade book for \n" << getCourseName() << "!"
<< endl;
}// end function displayMessage
private:
string courseName; // course name for this GradeBook
}; // end class GradeBook
// function main begins program execution
int main()
{
string nameOfCourse; // string of characters to store the course name
GradeBook myGradeBook; // create a GradeBook object named myGradeBook
//display initial value of courseName
cout << "Initial course name is:" << myGradeBook.getCourseName()
<< endl;
//prompt for, input and set course name
cout << "\n Please enter the course name:" << endl;
getline(cin, nameOfCourse); // read a course name with blanks
myGradeBook.setCourseName(nameOfCourse); // set the couse name
cout << endl;// outputs a blank line
myGradeBook.displayMessage();// display message with new course name
}//end main
|
定義建構子
//
// Instantiating multiple objects of the GradeBook class and using
// the GradBook constructor to specify the course name
// when each GradeBook object is created.
#include <iostream>
#include <string> //program uses C++ standard string class
using namespace std;
// GradeBook class definition
class GradeBook
{
public:
// constructor initializes courseName with string supplied as argument
GradeBook ( string name )
{
setCourseName( name ); //call set function to initialize courseName
}// end GradeBook constructor
//function to st the course name
void setCourseName( string name )
{
courseName = name; // stroe the coure name in the object
} // end function setCourseName
//fucntion to get the coursename
string getCourseName()
{
return courseName; // return object's courseName
} //end fucntion getCourseName
//display a welcomemessage to the GradeBook user
void displayMessage()
{
//call getCourseName to get the courseName
cout << "Welcome to the grade book for\n" << getCourseName()
<< "!" << endl;
} //end function displayMessage
private:
string courseName; // course name for this GradeBook
}; //end class GradeBook
//function main begins program execution
int main()
{
//create two GradeBook objects
GradeBook gradeBook1("CS101 introduction to C++ Programming");
GradeBook gradeBook2("CS102 Data Structures in C++");
//display initial value of courseName for each GradeBook
cout << "gradeBook1 created for course:" << gradeBook1.getCourseName()
<< "\ngradeBook2 created for course:" << gradeBook2.getCourseName()
<< endl;
} // end main
|
資料參考:
http://pydoing.blogspot.tw/2012/10/cpp-interface-and-implementation.html
留言
張貼留言