C++ classes
ในการเขียนโปรแกรมเชิงวัตถุ คลาสเป็น program-code-template สำหรับสร้างออบเจ็ค
ในภาษา C++ ให้เราสามารถสร้างคลาสที่มีแนวคิดขยายมากจากโครงสร้างข้อมูล คลาสสามารถถูกกำหนดโดยการใช้คำสั่ง
class
และมีรูปแบบดังนี้:class class_name
{
access_specifier_1:
member1;
access_specifier_2:
member2;
...
} object_names;
การสร้างคลาสคล้ายกับ structure ความแตกต่างคือคลาสสามารถมีฟังก์ชันเป็นสมาชิกของมันได้ และคลาสสามารถมีตัวกำหนดการเข้าถึง (Access specifier) เพื่อควบคุมการเข้าถึงสมากชิกในออบเจ็คได้
ในภาษา C++ นี่เป็นกำหนดการเข้าถึง
private
: สมาชิกประเภทนี้สามารถเข้าถึงได้โดยคลาสและออบเจ็คเดียวกัน และนี่เป็นค่าเริ่มต้นเมื่อเราปล่อยให้ว่างprotected
: สมาชิกประเภทนี้สามารถเข้าถึงได้ในคลาสเดียวกัน (friends) และ extended classespublic
: สมาชิกประเภทนี้สามารถเข้าถึงได้ทุกส่วนของโปรแกรม
เพื่อทำให้คุณเข้าใจดีขึ้น มาดูตัวอย่างเกี่ยวกับการสร้างโดยการใช้คลาส
class Circle
{
private:
int r;
public:
void setRadius(int n)
{
r = n;
};
float area(void)
{
return 3.14 * r * r;
};
float girth(void)
{
return 3.14 * 2 * r;
};
} cir1;
ในตัวอย่างนี้ เราได้สร้างคลาสชื่อว่า
Circle
ซึ่งมันมีสมาชิกที่เป็นตัวแปรหนึ่งตัว และสมาชิกที่เป็นฟังก์ชัน 3 ตัว สมาชิกหรือตัวแปร r
มีตัวกำหนดการเข้าถึงเป็น private
นั้นหมายความว่าตัวแปรนี้ไม่สามารถเข้าถึงได้จากภายนอกคลาส สมาชิกสามตัวต่อมาเป็นเมธอด (หรือฟังก์ชัน) ซึ่งเป็นเหมือนกับฟังก์ชันในภาษา C++ แต่ภายในคลาสเราเรียกว่าเมธอด เมธอดเหล่านี้มีตัวควบคุมการเข้าถึงเป็นแบบ public
นั่นหมายความว่ามันสามารถเข้าถึงได้จากนอกคลาส
มาดูตัวอย่างของโปรแกรมที่สร้างจากคลาสนี้
#include <iostream>
using namespace std;
class Circle
{
private:
int r;
public:
void setRadius(int n)
{
r = n;
};
float area(void)
{
return 3.14 * r * r;
};
float girth(void)
{
return 3.14 * 2 * r;
};
} cir1;
int main ()
{
int n;
cout << "Enter circle radius: ";
cin >> n;
cir1.setRadius(n);
cout << "Area " << cir1.area() << endl;
cout << "Girth " << cir1.girth() << endl;
return 0;
}
ในตัวอย่าง เราได้สร้างออบเจ็คชื่อว่า
cir1
จากคลาส Circle
ออบเจ็คนี้จะมีสมากชิกทุกอย่างเหมือนกับคลาสที่มันสร้างในตัวมันทั้งตัวแปรและฟังก์ชัน นั่นหมายความว่าคุณสามารถที่จะสร้างกราออบเจ็คก้ได้โดยใช้คลาสนี้ เมื่อออบเจ็คถูกสร้างแล้ว เราสามารถเข้าถึงข้อมูลภายในได้ตามของเหมาะสมตาม Access specifier ของมัน มาดูตัวอย่างเมื่อเรารันโปรแกรมนี้Enter circle radius: 8
Area 200.96
Girth 50.24
อีกตัวอย่างหนึ่งจะแนะนำให้คุณรู้จักกับตัวดำเนินการขอบเขต (
::
) ซึ่งเป็นเครื่องหมายเซมิโคลอนสองอัน ตัวดำเนินการนี้จะอนุญาติให้เราสามารถสร้างฟังก์ชันข้างนอกคลาสได้ เพราะว่าในคลาสนั้นเราสามารถสร้างฟังก์ชันได้เพียงหนึ่งบรรทัด เหมือนที่คุณเห็นในคลาส Circle
#include <iostream>
#include <string>
using namespace std;
class Person
{
public:
string first_name, last_name;
public:
string getFullname();
string getCountry(int);
};
string Person::getFullname()
{
return first_name + " " + last_name;
}
string Person::getCountry(int n)
{
if (n == 1)
return "US";
else if (n == 2)
return "Canada";
else if (n == 3)
return "Ukraine";
else
return "Unknown country";
}
int main()
{
Person p1;
p1.first_name = "Mateo";
p1.last_name = "Marcus";
Person p2;
p2.first_name = "Thomas";
p2.last_name = "Monte";
Person p3;
p3.first_name = "Dennis";
p3.last_name = "Ritchie";
cout << p1.getFullname() << " is in " << p1.getCountry(3) << endl;
cout << p2.getFullname() << " is in " << p2.getCountry(2) << endl;
cout << p3.getFullname() << " is in " << p3.getCountry(5) << endl;
return 0;
}
ในตัวอย่างนี้ เรามีคลาส
Person
ซึ่งมีสมาชิกแบบตัวแปรสองตัวคือ first_name
และ last_name
และมีสมาชิกที่เป็นฟังก์ชันสองฟังก์ชันคือ getFullname
และ getCountry
สังเกตุว่าเราไม่ได้สร้างฟังก์ชันไว้ในคลาส แต่เราย้ายมันออกมาข้างนอกคลาส เพราะว่ามันจะทำให้ง่ายกว่าในการสร้างภายในคลาสของมันเอง เพื่ออ้างถึงสมากใดๆ ข้างนอกคลาส Person
เราจะใช้ตัวดำเนินการขอบเขต Persion::getFullname
และ Persion::getCountry
เพื่อบอกให้คอมไพเลอร์รู้ และโปรแกรมจะให้ผลลัพธ์ดังต่อไปนี้Mateo Marcus is in Ukraine
Thomas Monte is in Canada
Dennis Ritchie is in Unknown country
สรุปเรื่อง class และ object
สรุป class และ object ด้วยตัวอย่าง Bank Account
*********************************************************************************************************************
ภาษา C มีแนวคิดในการเขียนโปรแกรมแบบโครงสร้างที่เรียกว่า Structure programming หรือแบบกระบวนการ (Procedure programming) โดยมีจุดประสงค์หลักในการเขียนโปรแกรมให้เครื่องคอมพิวเตอร์สามารถประมวลผลและวิเคราะห์ข้อมูล ซึ่งชุดคำสั่งของโปรแกรมที่เขียนขึ้นมาเพื่อใช้ในการแก้ปัญหาเฉพาะด้าน โดยจะทำการแยกปัญหาใหญ่ ๆ ออกเป็นส่วนย่อย ๆ เรียกว่าโมดูล (Module) ซึ่งอาจประกอบไปด้วยเฮดเดอร์ไฟล์ (Hrader file) หลาย ๆ ไฟล์ (*.h) และ ซอร์สไฟล์ (Source file) หลาย ๆ ไฟล์ (*.c) แล้วค่อยแก้ไขไปทีละส่วนจนกว่าจะได้ผลลัพธ์ที่ต้องการ ซึ่งประยุกต์มาจากวิธีคิดของมนุษย์นั่นเอง
ข้อเสียของการเขียนโปรแกรมเชิงโครงสร้าง
ถ้าขนาดของโปรแกรมไม่ใหญ่มาก ความซับซ้อนของโค้ดจะน้อยและไม่ก่อให้เกิดปัญหาและไม่ยุ่งยากในการที่จะพัฒนาโปรแกรม แต่หากขนาดของโปรแกรมใหญ่ขึ้น จะทำให้มีความซับซ้อนในแง่ของการเขียนโปรแกรม เนื่องจากแต่ละโมดูลจะมีความสัมพันธ์ต่อกันถ้ามีการแก้ไขเปลี่ยนแปลงบางส่วนในฟังก์ชันอาจกระทบกระเทือนทุกส่วนได้ ดังนั้นถ้าต้องเขียนโปรแกรมเพื่อแก้ปัญหาที่มีความซับซ้อนมาก การแก้ไขจะมีความซับซ้อนมากขึ้นด้วย ข้อจำกัดของการเขียนโปรแกรมเชิงโครงสร้างอีกประการหนึ่งคือ ไม่มีความยืดหยุ่นของการนำโปรแกรมที่เขียนแล้วกลับไปใช้ใหม่ เนื่องจากฟังก์ชันที่มีอยู่ในโปรแกรมเดิมอาจไม่มีความเหมาะสมที่จะนำไปใช้กับโปรแกรมใหม่เพราะฟังก์ชันนั้นถูกออกแบบให้ใช้กับการแก้ปัญหาใดปัญหาหนึ่งเท่านั้น
การเขียนโปรแกรมเชิงวัตถุ
จากข้อเสียดังกล่าวของภาษา C ทำให้มีการพัฒนาแก้ไขจุดบกพร่องดังกล่าวและเรียกว่าภาษาใหม่ที่สร้างขึ้นมาว่า C++ เป็นแนวคิดรูปแบบใหม่ที่นำมาใช้กันในปัจจุบัน ถึงแม้รูปแบบการเขียนจะค่อนข้างยากและมีความซับซ้อน แต่จะส่งผลดีต่อการแก้ไขโปรแกรมในระยะยาว ซึ่งแนวคิดนี้จะแยกปัญหา หรือแยกระบบงานออกเป็นส่วนย่อยเช่นกัน เพื่อลดความซับซ้อนให้น้อยลง ส่วนย่อยหรือโปรแกรมย่อยดังกล่าวจะเรียกว่าคลาส (Class) ภายในคลาสจะประกอบไปด้วยข้อมูลและฟังก์ชันการทำงาน ในการใช้งานโปรแกรมเมอร์จะสร้างตัวแทนของคลาสขึ้นมาทำงานเรียกว่าออบเจ็กต์ (Object) หากพูดให้เข้าใจได้ง่ายขึ้นออบเจ็กต์ คือ ตัวแปรของคลาสนั่นเองแต่แตกต่างจากตัวแปรปรกติตรงที่สามารถเก็บค่าได้มากกว่าหนึ่งค่าและสามารถเรียกฟังก์ชันการทำงานผ่านตัวแปรตัวนี้ได้เช่นเดียวกับที่เคยกล่าวถึงออบเจ็กต์ในเรื่องโครงสร้างข้อมูลนั่นเอง การเขียนโปรแกรมเชิงวัตถุจะพยามหาวัตถุจากโปรแกรมที่เคยสร้างมาแล้วมาประกอบในการสร้างโปรแกรมใหม่ทำให้ประหยัดเวลาในการสร้างโปรแกรมใหม่ และสามารถแก้ไขได้ง่ายเพราะวัตถุแต่ละชิ้นมีความเป็นอิสระต่อกันและวัตถุที่สร้างขึ้นมาแล้วสามารถนำกลับมาใช้ใหม่ได้อีก ซึ่งสอดคล้องกับหลักการในการนำมาใช้ใหม่ (Reusable)
วัตถุหรือออบเจ็กต์ (Object)
วัตถุในความหมายของการเขียนโปรแกรมจะต้องมีตำแหน่งหน่วยความจำของตัวเองเพื่อเก็บข้อมูลและการทำงานสำหรับการสื่อสารระหว่างออบเจ็กต์กับส่วนอื่นภายในโปรแกรม ดังนั้นเราจึงไม่ถือว่าตัวชี้เป็นออบเจ็กต์ถึงแม้ว่าตัวชี้จะมีตำแหน่งหน่วยความจำของตัวเองอยู่ในสแตกก็ตาม เนื่องจากข้อมูลที่อยู่ในหน่วยความจำเหล่านั้นเป็นตำแหน่งหน่วยความจำของวัตถุอื่น ซึ่งไม่สามารถนำมาใช้งานโดยตรงได้ (ต้องอาศัยการเข้าถึงโดยอ้อม) และตัวแปรทั่วไปจะไม่ถูกมองว่าเป็นออบเจ็กต์เช่นกันเนื่องจากมีความสามารถแค่การเก็บข้อมูลแต่ไม่มีฟังก์ชันการทำงานใด ๆ อยู่ภายในตัวแปร
นอกจากคำว่า ตัวแปร ตัวชี้ และ ออบเจ็กต์แล้วยังมีอีกคำหนึ่งที่จำเป็นต้องกล่าวถึงได้แก่คำว่า อินสแตนซ์ (Instance) ซึ่งหมายถึงสิ่งที่ทำหน้าที่เป็นตัวแทนข้อมูลซึ่งต้องมีตำแหน่งหน่วยความจำของตัวเองที่แน่นอนโดยไม่สนใจว่ามีฟังก์ชันการทำงานหรือไม่ ซึ่งจะประกอบไปด้วย ตัวแปร และ ออบเจ็กต์นั่นเอง คำว่าอินสแตนซ์เป็นคำที่ใช้เรียกรวมตัวแทนข้อมูลทั้งสองประเภทดังกล่าวในกรณีที่แน่ใจแล้วว่าเรื่องราวที่กล่าวถึงนั้นสามารถทำงานได้กับทั้งตัวแปรและออบเจ็กต์
เราจะถือว่าออบเจ็กต์เป็นตัวแทนของคลาสโดยคลาสจะทำหน้าที่เก็บพฤติกรรมที่ใช้งานร่วมกันของวัตถุที่เป็นตัวแทนของคลาส เพื่อให้เห็นภาพชัดเจนขึ้น หากเราทำการสร้างรถขึ้นมาหนึ่งคัน เราจะถือว่ารถที่ถูกผลิตออกมานั้นเป็นออบเจ็กต์ และแบบแปลนพิมพ์เขียวที่ใช้ในการออกแบบรถ และข้อมูลจำเพาะต่าง ๆ เช่น การทำงานของเครื่องยนต์ การจุดระเบิด ฯ เป็นคลาสดังนั้นก่อนที่จะทำการสร้างรถได้ต้องมีการสร้างแบบพิมพ์เขียวของรถขึ้นมาก่อน ซึ่งหมายความว่าก่อนที่จะทำการสร้างออบเจ็กต์ขึ้นมาได้จำเป็นต้องมีการสร้างหรือนิยามคลาสขึ้นมาก่อน และพฤติกรรมที่สามารถใช้งานร่วมกันได้ของวัตถุหมายถึงพฤติกรรมของรถที่มีได้เหมือน ๆ กัน เช่น การสตาร์ทเครื่อง การเบรก การเร่งเครื่อง รวมไปถึงองค์ประกอบพื้นฐาน เช่น ล้อ ตัวถัง กระโปรงรถ เป็นต้น
คลาส (Class)
สิ่งต่าง ๆ ในโลกความเป็นจริงเราสามารถอธิบายได้ด้วย 2 องค์ประกอบหลัก คือ ข้อมูลและพฤติกรรมการทำงานตัวอย่าง เช่น พนักงาน (employees) เราสามารถอธิบายถึงตัวพนักงานในโลกความเป็นจริงได้ดังนี้
1. เรามีพนักงานที่แตกต่างกันหลายประเภทดังนี้
- พนักงานทั่วไป (employee)
- ผู้จัดการ (manager)
- ผู้ดูแล (supervisor)
ประเภทหรือลักษณะต่าง ๆ ที่เป็นองค์รวมในโลกความเป็นจริงสามารถแปลงออกมาเป็นโครงสร้างข้อมูลหรือคลาสในมุมมองของการเขียนโปรแกรมได้
2. สำหรับพนักงานจะประกอบไปด้วยข้อมูลดังนี้
- ชื่อ (name)
- อัตราเงินเดือน (pay rate)
ข้อมูลในโลกความเป็นจริงซึ่งจะถูกเปลี่ยนเป็นตัวแปรสมาชิกของคลาส
3. นอกจากนี้เรายังต้องการการทำงานบางอย่างเพิ่มเติมเช่น
- การจ้างพนักงาน
- การดึงข้อมูลต่าง ๆ ของพนักงาน เช่น ชื่อ อัตราเงินเดือนฯ เป็นต้น
- การคำนวณอัตราเงินเดือน
สิ่งที่กล่าวมาข้างต้นถือเป็นพฤติกรรมหรือหน้าที่การทำงานในโลกความเป็นจริงซึ่งหมายถึงการทำงานหรือฟังก์ชัน (function) ในคลาส
จากแนวคิดดังกล่าวการเขียนโปรแกรมเชิงวัตถุจึงเป็นการเขียนโปรแกรมที่ประกอบไปด้วย ข้อมูลและฟังก์ชันที่เกี่ยวข้องกันมารวมไว้ภายในคลาสเดียวกันทำให้สามารถนำเอาออบเจ็กต์ของคลาสมาอธิบายถึงการทำงานเหล่านี้ได้ คลาสจะมีลักษณะในการประกาศสำหรับ C++ ได้หลายลักษณะซึ่งมีโครงสร้างพื้นฐานที่สุดดังต่อไปนี้
รูปที่ 1. โครงสร้างพื้นฐานของคลาส
รูปด้านบนเป็นตัวอย่างของการประกาศคลาสพื้นฐานที่ง่ายที่สุดซึ่งจะเริ่มต้นจากคำสำคัญ class แล้วตามด้วยชื่อของคลาสที่ต้องการ ภายในขอบเขตของการประกาศคลาสจะประกอบไปด้วยการประกาศตัวแปรและฟังก์ชันสมาชิกของคลาส และสิ้นสุดด้วยสัญลักษณ์ “;” เป็นการบอกถึงจุดสิ้นสุดของการประกาศคลาส การสร้างฟังก์ชั่นการทำงานของคลาสใน C++ สามารถทำได้สองลักษณะคือ
- เขียนการทำงานของฟังก์ชั่นไว้ในส่วนประกาศของคลาส (class header)
- เขียนการทำงานของฟังก์ชั่นแยกออกจากส่วนประกาศของคลาส
การเขียนการทำงานของฟังก์ชั่นไว้ในส่วนประกาศของคลาส
วิธีนี้สามารถทำงานได้ดีกับคลาสที่มีการทำงานไม่ซับซ้อนมากเกินไป หากเป็นคลาสที่มีขนาดใหญ่จะทำให้ไล่การทำงานได้ลำบาก
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| class CGameUnit{ int hp; int shield; int damage; void Attack() { cout << "Attack" << endl; } void Defense() { cout << "Defense" << endl; } }; |
ในตัวอย่างด้านบนเป็นการสร้างคลาส CGameUnit สำหรับตัวละครในเกมโดยประกอบไปด้วยตัวแปรสมาชิกหรือคุณสมบัติ (Attribute) ได้แก่ hp, damage, shield และมีฟังก์ชันการทำงานได้แก่ CGameUnit(), Attack(), และ Defense()
การเขียนการทำงานของฟังก์ชั่นแยกออกจากส่วนประกาศของคลาส
วิธีนี้จะทำการเขียนฟังก์ชั่นการทำงานแยกออกจากส่วน header ของคลาสทำให้ส่วนของการประกาศคลาสดูเข้าใจได้ง่ายกว่าแบบแรกดังลักษณะต่อไปนี้
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| class CGameUnit{ int hp; int shield; int damage; void Attack(); void Defense(); }; void CGameUnit::Attack() { cout << "Attack" << endl; } void CGameUnit::Defense() { cout << "Defense" << endl; } |
โค้ดที่ต้องเขียนจะมีขนาดใหญ่ขึ้นกว่าเดิมเล็กน้อยแต่สะดวกในการไล่การทำงานของโปรแกรม สำหรับการเขียนการทำงานของฟังก์ชันแยกออกจากส่วนประกาศคลาส จะเขียนเช่นเดียวกับฟังก์ชันทั่วไปใน C++ เพียงแต่ต้องระบุให้คอมไพเลอร์รู้ว่าฟังก์ชันที่เขียนขึ้นนี้เป็นของคลาสที่เราได้ทำการสร้างขึ้น ด้วยการเพิ่มชื่อคลาสและตามด้วยสัญลักษณ์ double colon “::” ไว้หน้าชื่อฟังก์ชัน สำหรับสัญลักษณ์ “::” จะมีชื่อเฉพาะว่า Operator of Scope ซึ่งหมายถึงความเป็นเจ้าของโดยฝั่งซ้ายของสัญลักษณ์นี้จะเป็นเจ้าของของฝั่งขวา ตัวอย่าง เช่น CGameUnit::Attack() หมายความว่า ฟังก์ชัน Attack() เป็นของคลาส CGameUnit นั่นเอง
องค์ประกอบหลักของการเขียนโปรแกรมเชิงวัตถุ
ในการเขียนโปรแกรมเชิงวัตถุจะมีการทำงานที่เกี่ยวข้องกับคลาสและออบเจ็กต์อย่างหลีกเลี่ยงไม่ได้
ซึ่งมีหลักการที่ใช้ในการออกแบบการทำงานของคลาสดังต่อไปนี้
1. Abstraction เป็นการคัดเลือกเอาเฉพาะองค์ประกอบของข้อมูลที่จำเป็นในการแก้ปัญหามาใช้ในการออกแบบคลาส
2. Encapsulation การซ่อนข้อมูลของคลาสโดยการกำหนดสิทธิในการเข้าถึงข้อมูลเพื่อความชัดเจนและง่ายในการใช้งานในการใช้งานของคลาส
3. Inheritance เป็นการสืบทอดคุณสมบัติของคลาสเพื่อช่วยให้สามารถนำเอาฟังก์ชันการทำงานต่าง
ๆ กลับมาใช้ใหม่รวมไปถึงการทำให้โค้ดอ่านได้ง่ายขึ้น
4. Polymorphism เป็นการพูดถึงฟังก์ชันการทำงานในคลาสที่มีชื่อเดียวกันแต่มีพฤติกรรมการทำงานที่แตกต่างกัน
ในตำราบางเล่มอาจเพิ่มการดักจับข้อผิดพลาด ( Exception Handling) เป็นปัจจัยที่ห้าในองค์ประกอบหลักของการเขียนโปรแกรมเชิงวัตถุเช่นกัน
Abstraction
Abstraction
เป็นขั้นตอนแรกของการเขียนโปรแกรมเชิงวัตถุ
ซึ่งเป็นการทำงานในขั้นตอนของการออกแบบสำหรับคลาส
โดยทำการคัดเลือกเอาเฉพาะส่วนที่มีองค์ประกอบสำคัญในการแก้ปัญหาเท่านั้นในการทำงาน
ตัวอย่างเช่น
หากปัญหาเป็นการเขียนโปรแกรมสำหรับคำนวณค่าเงินเดือนของพนักงานหนึ่งคน เราสามารถวิเคราะห์ได้ว่าพนักงานหนึ่งคนอาจประกอบไปด้วยข้อมูลต่อไปนี้
·
name
ชื่อของพนักงาน
·
gender
เพศของพนักงาน
·
age
อายุของพนักงาน
·
height
ความสูงของพนักงาน
·
weight
น้ำหนักของพนักงาน
·
hour
ชั่วโมงการทำงาน
·
payrate
รายได้ต่อชั่วโมง
และพนักงานแต่ละคนจะมีการทำงานหรือพฤติกรรมดังต่อไปนี้
·
Eating()
กินข้าว
·
Walking() การเดิน
·
Driving()
ขับรถ
·
CalculateSaraly()
การคิดเงินเดือน
นี่คือส่วนหนึ่งของข้อมูลที่สามารถมีได้ในตัวพนักงานคนหนึ่ง
แต่ในความเป็นจริงแล้วปัญหาที่วิเคราะห์คือการเขียนโปรแกรมเพื่อวิเคราะห์หาค่าเงินเดือนของพนักงานซึ่งมีข้อมูลที่คัดเลือกเพื่อนำมาใช้ในการแก้ปัญหาจะได้แก่
พนักงานเป็นใคร มีชั่วโมงการทำงานเท่าไหร่ รายได้ต่อชั่วโมงเป็นเท่าใด
และรวมไปถึงพฤติกรรมในการทำงานได้แก่การคำนวณหาเงินเดือน
ดังนั้นการคัดเลือกเฉพาะส่วนที่เกี่ยวข้องกับปัญหาทำให้ได้คลาสที่ใช้ในการแก้ปัญหาดังนี้
1
2
3
4
5
6
|
class CEmployee{
char name[32];
float workhour;
int payrate;
float CalculateSaraly();
};
|
ดังนั้น Abstraction จึงหมายถึงการกำจัดข้อมูลที่ไม่เกี่ยวข้องทิ้งไปให้เหลือเฉพาะข้อมูลที่จำเป็นต่อการแก้ปัญหาเท่านั้น
เนื่องจากเป็นไปไม่ได้และไม่จำเป็นที่จำนำเอาคุณสมบัติทุกข้อที่มีจริงของวัตถุนั้นมาเขียนโปรแกรมดังตัวอย่างของคลาสพนักงานข้างต้น
Encapsulation
การซ่อนข้อมูล หรือ Encapsulation คือ
ความสามารถในการจัดการกับระดับการเข้าถึงข้อมูลภายในของคลาสแบ่งออกได้เป็นสามระดับคือ
private, protected และ public คำสำคัญหรือ keyword เหล่านี้ใช้ได้กับคลาส และโครงสร้างข้อมูล
ซึ่งใช้ระบุระดับการเข้าถึงหรือระดับในการมองเห็นจากคลาสอื่น ๆ
สาเหตุที่ต้องมีการซ่อนข้อมูลเนื่องจากในปัจจุบันการพัฒนาโปรแกรมมักจะทำงานกันเป็นทีมและแยกส่วนกันพัฒนา
ดังนั้นจึงมีการใช้การซ่อนข้อมูลที่จำเป็นบางส่วนเพื่อป้องกันไม่ให้คนอื่นในทีมเปลี่ยนแปลงค่าของสมาชิกภายในคลาส
ผ่านทางการทำงานต่าง ๆ
ที่เป็นสมาชิกภายในของคลาสที่สร้างขึ้นจนทำให้เกิดข้อผิดพลาดในการทำงานได้
ตัวอย่าง เช่น หากเราทำการสร้างคลาสสำหรับเครื่องยนต์ดังนี้
1
2
3
4
5
6
7
8
9
|
class CEngine{
public:
float s;
float t;
float GetSpeed()
{
return
s/t;
}
};
|
จากโค้ดตัวอย่างภายในคลาส CEngine มีฟังก์ชันสมาชิก คือ GetSpeed() ซึ่งทำหน้าที่ในการหาความเร็วของเครื่องยนต์
จะเกิดอะไรขึ้นหากสมาชิกอื่นในทีมมีการเรียกใช้งานดังโค้ดต่อไปนี้
1
2
3
4
5
6
7
|
void main(void)
{
CEngine
engine;
engine.s =
100;
engine.t =
0;
cout
<< "Speed = " << engine.GetSpeed() << endl;
}
|
หากสังเกตจะเห็นได้ว่ามีการกำหนดค่า t เป็น 0 จากนั้นเรียกใช้งานฟังก์ชัน GetSpeed() ผ่านทางออบเจ็กต์ engine ของคลาส CEngine ภายในฟังก์ชันนี้จะทำการหาค่าความเร็วของเครื่องยนต์ด้วยการนำระยะทาง
(s) หารด้วยเวลา (t) แต่เนื่องจากตัวหารเป็น
0 ทำให้เกิดข้อผิดพลาดในโปรแกรมได้ ซึ่งข้อผิดพลาดนี้เกิดจาก
การกำหนดค่า t ให้เป็น 0 อาจเกิดจากความเผอเรอ หรือไม่เข้าใจการทำงานภายในของฟังก์ชัน GetSpeed() เพื่อแก้ปัญหานี้เราจึงต้องอาศัยการกำหนดระดับในการเข้าถึงข้อมูลเพื่อป้องกันปัญหาดังกล่าว
ดังนั้นจึงกล่าวได้ว่าคำสำคัญ private, protected และ public เป็นการกำหนดระดับการซ่อนข้อมูลของ
ตัวแปร ฟังก์ชั่น ที่เป็นสมาชิกของคลาสออกจากฟังก์ชันภายนอกอื่น ๆ
หรือจากออบเจ็กต์ของตัวคลาสเองซึ่งมีรายละเอียดของการเข้าถึงแต่ละระดับดังต่อไปนี้
private
ตัวแปรและฟังก์ชั่นสมาชิกต่าง ๆ
ภายในคลาสสามารถเรียกใช้งานได้จากฟังก์ชั่นของตัวคลาสที่เป็นเจ้าของเท่านั้น
เราจะใช้คำสงวน private กับข้อมูลที่มั่นใจแล้วว่าไม่ยุ่งเกี่ยวกับการทำงานภายนอกอื่น
ๆ ในโปรแกรมจะมีการใช้งานส่วนข้อมูลที่อยู่ใน private เฉพาะคลาสนี้เท่านั้น ตัวอย่าง เช่น
หากเราจะสร้างคลาสของมนุษย์ขึ้นมา ส่วนที่ควรจะอยู่ระดับการเข้าถึงแบบ private จะได้แก่ ลายนิ้วมือ ลายม่านตา สปีชีส์ เป็นต้น
จะเห็นว่าข้อมูลเหล่านี้เป็นข้อมูลที่แสดงถึงอัตลักษณ์ของมนุษย์และมีคุณสมบัติเฉพาะเป็นของตัวเอง
ซึ่งสามารถแสดงตัวอย่างของคลาสได้ดังต่อไปนี้
1
2
3
4
5
6
7
|
class CHuman{
private:
int finger_print;
int iris;
int species;
void SetFingerPrint(int
fingerprint);
};
|
ภายใต้ส่วนประกาศ private จะเห็นได้ว่าเราสามารถประกาศได้ทั้งตัวแปรสมาชิกและฟังก์ชันสมาชิก
ซึ่งส่วนประกาศที่ตามหลังการประกาศในการเข้าถึงข้อมูลทั้งหมดจะถือว่าอยู่ในระดับการเข้าถึงดังกล่าวด้วย
ทั้งนี้ภายในคลาสหนึ่ง ๆ เราสามารถประกาศระดับการเข้าถึงวางไว้ในตำแหน่งใดก็ได้ภายในส่วนประกาศคลาส
และสามารถประกาศซ้ำได้มากกว่าหนึ่งครั้ง
จะเห็นได้ว่าคุณสมบัติเหล่านี้เป็นคุณสมบัติที่ไม่สามารถเปลี่ยนแปลงได้
หากจะทำการเปลี่ยนแปลงต้องอาศัยลักษณะที่ไม่เป็นไปตามธรรมชาติ
หรือเป็นการฝืนกฎของธรรมชาตินั่นเอง ซึ่งจะกล่าวถึงในเรื่องของคำสำคัญ “friend”
Private by Default
โดยปรกติหากไม่กำหนดระดับการเข้าถึงไว้ ทุก ๆ
สมาชิกของคลาสจะมีสถานะเป็น private by Default โดยอัตโนมัติ
protected
ตัวแปรและฟังก์ชั่นต่าง ๆ ที่อยู่ใน protected สามารถเรียกใช้งานได้จากฟังก์ชั่นของตัวคลาสที่เป็นเจ้าของและฟังก์ชันของคลาสที่สืบถอดจากคลาสนี้เท่านั้น
ซึ่งจะเข้าใจในส่วนนี้ได้ต้องรู้จักการสืบทอดคุณสมบัติ หรือ Inheritance ของคลาสก่อน ในการเขียนโปรแกรมเชิงวัตถุนั้นเราสามารถสร้างการสืบทอดคุณสมบัติได้
เช่นเดียวกับการถ่ายทอดพันธุกรรมของสิ่งมีชีวิตที่เป็นการถ่ายทอดคุณสมบัติจากบรรพบุรุษไปยังลูกหลาน
คลาสที่เป็นต้นทางของคุณสมบัติจะเรียกว่าคลาสแม่ (Parent class หรือ Super class) และคลาสที่ได้รับการถ่ายทอดคุณสมบัตินั้นจะเรียกว่าคลาสลูก
(Child class หรือ Sub class) ตัวอย่าง เช่น
กรุ๊ปเลือด เพศ ชื่อ นามสกุล
จะเห็นได้ว่าคุณสมบัติเหล่านี้แม้จะมีในคลาสแม่แต่จะถูกส่งต่อไปให้ลูกด้วยเช่นกัน
เพียงแต่จะมีรายละเอียดที่แตกต่างกัน เช่น แม่มีเพศเป็นผู้หญิง
แต่ลูกอาจจะมีเพศเป็นชายเป็นต้น
1
2
3
4
5
6
7
8
9
10
11
12
|
class CHuman{
private:
int finger_print;
int iris;
int species;
void SetFingerPrint(int
fingerprint);
protected:
char blood_type;
char gender;
char name[32];
char surname[32];
};
|
ลักษณะข้อมูลที่ควรอยู่ในระดับการเข้าถึงแบบ Protected ควรเป็นข้อมูลที่สามารถเปลี่ยนแปลงได้แต่ไม่ได้หมายความว่าจะเปลี่ยนแปลงได้ง่ายนัก
หากจะทำการเปลี่ยนแปลงจะเป็นการเปลี่ยนแปลงจากตัวเจ้าของเป็นคุณสมบัติเหล่านั้นเป็นคนตัดสินใจเองเท่านั้นโดยทั่วไปเราจะทำการสร้างฟังก์ชันขึ้นมารองรับการเปลี่ยนแปลงค่าเหล่านี้โดยประกาศไว้ในส่วนของ
public จะไม่นิยมให้เข้าถึงข้อมูลผ่านทางตัวแปรสมาชิกในคลาสโดยตรง
public
ตัวแปรและฟังก์ชั่นต่าง ๆ ที่อยู่ใน public สามารถเรียกใช้งานได้จากออบเจกต์ของคลาส ตัวแปรและฟังก์ชันสมาชิกที่อยู่ภายในคลาสนี้เป็นข้อมูลที่สามารถเปลี่ยนแปลงได้จากภายนอกผ่านทางออบเจ็กต์ของคลาส
ตัวอย่าง เช่น สีผม เสื้อผ้า รองเท้า
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
class CHuman{
private:
int finger_print;
int iris;
int species;
void SetFingerPrint(int
fingerprint);
protected:
char blood_type;
char gender;
char name[32];
char surname[32];
public:
char hair_color;
char shirt;
char shoes;
CHuman();
};
|
จะเห็นได้ว่าข้อมูลที่ยกตัวอย่างมาเป็นข้อมูลที่มีการเปลี่ยนแปลงได้บ่อยและไม่มีผลกับภายในของตัวบุคคลที่เป็นเจ้าของคุณสมบัติเหล่านี้มากนัก
ในการใช้งานหมายความว่าฟังก์ชันต่าง ๆ
จากภายนอกคลาสสามารถกำหนดคุณสมบัติหรือตัวแปรสมาชิกของคลาสเหล่านี้ได้ผ่านทางออบเจ็กต์ของคลาสโดยตรง
ออบเจ็กต์ของคลาสจะเข้าถึงได้เฉพาะส่วนที่เป็น public ของคลาสเท่านั้น
Accessor และ Mutator Function
ในบางครั้งมีความจำเป็นต้องเข้าถึงข้อมูลที่อยู่ในส่วนของ private และ protected ผ่านทางออบเจ็กต์ของคลาส
ซึ่งโดยทั่วไปแล้วจะทำการสร้างฟังก์ชันสมาชิกของคลาสไว้ในส่วน public เพื่อจัดการกับข้อมูลดังกล่าว โดยแบ่งออกเป็นฟังก์ชัน Accessor และ Mutator ซึ่งเป็นชื่อที่ใช้เรียกฟังก์ชันที่มีลักษณะการทำงานดังต่อไปนี้
Accessor
Accessor
คือฟังก์ชั่นของคลาสโดยเรียกผ่านการทำงานของฟังก์ชันจากออบเจ็กต์ของคลาส
ซึ่งอาจจะเป็นฟังก์ชันที่มีการคืนค่าออกมาหรือการแสดงผล
แต่จะไม่มีการเปลี่ยนแปลงค่าของตัวแปรสมาชิกภายในของคลาส ตัวอย่าง เช่น
1
2
3
4
5
6
7
|
class A{
private:
int x;
public:
int GetX(){
return x;}
void DisplayX(){cout
<< “X is”<<x;}
};
|
ฟังก์ชัน GetX() ของคลาส A มีการคืนค่าของตัวแปรของคลาสจึงเป็น Accessor function ในขณะเดียวกันฟังก์ชัน DisplayX() มีการแสดงค่าของตัวแปรของคลาสออกมาสู่ภายนอกจึงเป็น Accessor function
Mutator
Mutator
คือฟังก์ชั่นที่มีการเปลี่ยนแปลงค่าภายในของตัวแปรภายในของคลาสผ่านทางออบเจ็กต์
ดังตัวอย่างต่อไปนี้
1
2
3
4
5
6
7
|
class A{
private:
int x;
public:
void SetX(int
x){this->x=x;}
void SetX(){x=5;}
};
|
ตัวอย่างฟังก์ชันทั้งสองถือว่าเป็น Mutator function เนืองจากมีการเปลี่ยนแปลงค่าตัวแปรสมาชิกของคลาส
สรุป Encapsulation
ในการทำงานจริงบางครั้งการกำหนดระดับการเข้าถึงอาจเป็นไปได้ยาก
เนื่องจากลักษณะและมุมมองต่อปัญหาของแต่ละคนย่อมไม่เหมือนกัน ขึ้นอยู่กับว่ามองประเด็นของปัญหาในมุมมองใดเป็นสำคัญ
อาจมีบางคนคิดว่าให้ใส่เป็น private กับสมาชิกภายในคลาสทุกตัวเพราะ
Encapsulation เน้นความปลอดภัยของข้อมูลดังนั้นน่าจะดีกว่าถ้าให้ข้อมูลทุกตัวปลอดภัย
ซึ่งความคิดนี้ไม่ถือว่าถูกและผิดแต่อย่างใด แต่ขอให้ลองนึกถึงการที่ต้องสร้างฟังก์ชัน
Accessor และ Mutator สำหรับทุกตัวแปรสมาชิกในคลาสว่าเป็นงานที่เยอะเพียงใด
และจำเป็นหรือไม่ ดังนั้นในที่นี้จึงแนะนำหลักการคร่าว ๆ
สำหรับการพิจารณาระดับการเข้าถึงภายในคลาสดังนี้
1. หากรู้ว่าตัวแปรและฟังก์ชันสมาชิกภายในคลาส ถูกเปลี่ยนค่าจะทำให้เกิดความเสียหายกับการทำงานของโปรแกรมแน่นอนให้ใส่ไว้ในส่วนของ
private เพื่อป้องกันการเปลี่ยนแปลงค่าเหล่านั้น
2. หากคลาสที่สร้างขึ้นมีการส่งต่อไปยังคลาสลูกแน่นอนให้กำหนดไว้ในส่วนของ
protected
3. หากไม่แน่ใจว่าข้อมูลที่ต้องการอยู่ในส่วนใดให้กำหนดไว้ในส่วนของ private จนเมื่อเห็นภาพการทำงานของโปรแกรมชัดเจนขึ้น
ค่อยกำหนดระดับการเข้าถึงกับข้อมูลนั้นใหม่
คอนสตรัคเตอร์
คอนสตรัคเตอร์เป็นฟังก์ชันพิเศษที่จะถูกเรียกใช้เมื่อออบเจ็คถูกสร้าง เป้าหมายของมันเพื่อสำหรับกำหนดค่าเริ่มต้นให้กับออบเจ็ค คอนสตรัคเตอร์ใช้ชื่อเดียวกับคลาส มาดูตัวอย่างคลาสที่มีคอนสตรัคเตอร์
#include <iostream>
using namespace std;
class Circle
{
public:
int r;
public:
Circle(int);
float area (void);
};
Circle::Circle(int a)
{
r = a;
}
float Circle::area()
{
return 3.14 * r * r;
};
int main()
{
Circle c1(2);
Circle c2(5);
cout << "Circle 1's area = " << c1.area() << endl;
cout << "Circle 2's area = " << c2.area() << endl;
return 0;
}
ในตัวอย่าง เราได้เปลี่ยนแปลงโค้ดบางส่วนของคลาส
Circle
จากตัวอย่างก่อนหน้า ในตัวอย่างนี้เราได้เพิ่มคอนสตรัคเตอร์เข้ามา คอนสตรัคเตอร์เป็นฟังก์ชันพิเศษที่มีชื่อเหมือนคลาสของมัน มันสามารถมีพารามิเตอร์จำนวนเท่าไหร่ก็ได้เหมือนฟังก์ชันทั่วไป ในตัวอย่างจะเห็นว่าเรามี 1 พารามิเตอร์คือรัศมีของวงกลมที่จะถูกกำหนดเมื่อออบเจ็คถูกสร้าง และนี่เป็นผลลัพธ์ของโปรแกรมCircle 1's area = 12.56p
Circle 2's area = 78.5
Overloading constructors
Overloading constructors เป็นคอนสตรัคเตอร์ที่มีชื่อเดียวกันแต่มีพารามิเตอร์หรือประเภทข้อมูลที่แตกต่างกัน คอมไพเลอร์จะตัดสินใจอัตโนมัติที่จะเลือกใช้ที่มีพารามิเตอร์และประเภทข้อมูลตรงกันเมื่อออบเจ็คถูกสร้าง มาดูตัวอย่าง
Circle::Circle()
{
}
Circle::Circle(float a)
{
r = (int) a;
}
Circle::Circle(int a)
{
r = a;
}
Circle::Circle(int a, int b)
{
r = a + b;
}
สอน C++: การทำ function overloading เบื้องต้น
ในตัวอย่างเรามี 4 Overloading constructors แต่ละคอนสตรัคเตอร์จะมีจำนวนพารามิเตอร์และประเภทข้อมูลที่ต่างกัน
ในบทนี้ เราได้ครอบคลุมถึงพื้นฐานเกี่ยวกับคลาสในภาษา C++ อย่างไรก็ตาม คลาสยังมีเนื้อหามากกว่านี้ ที่ยังไม่ได้กล่าวถึง
************************************************************************************
https://medium.com/@iBookky/%E0%B8%A3%E0%B8%B9%E0%B9%89%E0%B8%88%E0%B8%B1%E0%B8%81-class-object-%E0%B9%80%E0%B8%9A%E0%B8%B7%E0%B9%89%E0%B8%AD%E0%B8%87%E0%B8%95%E0%B9%89%E0%B8%99-250044991f48
https://www.cp.eng.chula.ac.th/~chate/2110210/objectAndClasses.pdf