/ OOP

[365 วันแห่งโปรแกรม #day25] Constructor

วันที่ยี่สิบห้าของ ‪#‎365วันแห่งโปรแกรม‬ วันนี้เราจะมีคุยกันเรื่อง Constructor


Constructor คืออะไร?

Constructor เป็นฟังก์ชันพิเศษของคลาสที่จะถูกเรียกขณะสร้าง object ของคลาสนั้นๆ การสร้าง Constructor นั้นทำเหมือนฟังก์ชันปกติ แต่ต้องใช้ชื่อเดียวกับคลาส และไม่มี return type (ไม่มีเลย ไม่ต้องใส่ void)

ตัวอย่าง Constructor ของคลาส Rectangle

class Rectangle{
public:
	int width;
	int height;
	Rectangle(){
	}
};

จะเห็นว่าภายในคลาส Rectangle มีฟังก์ชันชื่อ Rectangle อยู่ และฟังก์ชันนี้ไม่มี return type นั่นหมายความว่าฟังก์ชันนี้เป็น Constructor

Constructor มีไว้ทำอะไร?

Constructor นั้นมีไว้สำหรับ initial การทำงานของคลาส เช่น ใช้ในการสร้าง member object หรือ ตั้งค่าเริ่มต้นต่างๆ ให้กับคลาสนั้นๆ

ตัวอย่าง Constructor ที่มีการ intitial member

class Rectangle{
public:
	int width;
	int height;
	Rectangle(){
		width = 0;
		height = 0;
	}
};

จากตัวอย่างที่แล้วจะเห็นว่าใน Constructor นั้นมีการกำหนดค่าของ width และ height ให้เป็น 0

Constructor มีพารามิเตอร์ได้ไหม?

ได้แน่นอน เพราะ Constrcutor นั้นเป็นฟังก์ชัน ดังนั้นเราจึงสามารถส่งพารามิเตอร์เข้าไปเพื่อกำหนดค่า property ของ object นั้นๆ หรือทำอะไรบางอย่างได้ โดย Constrcutor ที่มีพารามิเตอร์นี้ เราเรียกว่า Parameterized constructor

ตัวอย่าง Parameterized constructor

class Rectangle{
public:
	int width;
	int height;
	Rectangle(int width, int height){
		this->width = width;
		this->height = height;
	}
};

จากตัวอย่างนี้จะมีการรับค่า width และ height เข้าไปเพื่อตังเป็นค่าเริ่าต้นให้กับ width และ height ของ object ของ Rectangle

แล้วมี Constructor หลายตัวได้ไหม?

แน่นอนว่าได้ Constructor นั้นมีคุณสมบัติของ Polymorphism แบบ Overloading เช่นเดียวกันกับฟังก์ชันทั่วไป

ตัวอย่างการ Overload Constructor

class Rectangle{
public:
	int width;
	int height;
	Rectangle(){
		width = 0;
		height = 0;
	}
    Rectangle(int width, int height){
		this->width = width;
		this->height = height;
	}
};

จากตัวอย่างนี้จะเห็นว่ามีทั้ง Constructor ที่รับพารามิเตอร์และไม่รับพารามิเตอร์ ซึ่งเวลาผู้ใช้สร้าง object ของ Rectangle ถ้าใส่ width และ height ก็จะเข้า Constructor ที่มีพารามิเตอร์เป็น int,int แต่ถ้าไม่ใส่ก็จะเข้าอีกอันหนึ่ง

แล้วถ้าไม่ประกาศ Constructor ล่ะได้ไหม?

จริงๆ แล้วเรื่องนี้ขึ้นอยู่กับภาษาโปรแกรม แต่ในภาษาโปรแกรมส่วนใหญ่มักจะมี Default Constructor ให้ โดยเป็น Constructor ที่ไม่รับพารามิเตอร์ และไม่ทำอะไรนอกจาก เรียก Constructor ของ super class ต่อ

ฟังก์ชันอื่นสามารถเรียก Constructor ของคลาสตัวเองขึ้นมาทำงานได้ไหม

ไม่ได้ เพราะ Constructor จะต้องทำงานเฉพาะตอนสร้าง Object เท่านั้น แต่อย่างไรก็ตาม Constructor สามารถเรียก Constructor อื่นของคลาสตัวเองได้ ซึ่งวิธีการเรียกนั้นก็แล้วแต่ข้อกำหนดของภาษาโปรแกรมนั้นๆ

ตัวอย่างการเรียก Constructor อื่น จากอีก Constructor

class Rectangle{
public:
	int width;
	int height;
	Rectangle() :Rectangle(0, 0) {
	}
	Rectangle(int width, int height){
		this->width = width;
		this->height = height;
	}
};

จากตัวอย่างจะเห็นว่าถ้าเราสร้าง object ของ Rectangle โดยไม่ใส่พารามิเตอร์ Constructor แบบไม่รับพารามิเตอร์จะทำงานโดยการไปเรียก Constructor อีกตัวหนึ่ง โดยส่งพารามิเตอร์ width และ height เป็น 0

ปกติแล้วเราจะสร้าง Constructor หนึ่งตัวที่รับพารามิเตอร์ทุกอย่าง ที่ต้องการให้รับได้ แล้วทำการ overload แบบ currying (ตัดทอนพารามิเตอรืออกไป) เพื่อให้มี Constructor ที่เรียกใช้ง่ายๆ แล้วให้ทุก Constructor ทำการเรียกไปยัง Constructor หลักตัวเดียวกัน เพื่อเวลาแก้จะได้แก้แค่ที่เดียว

Constructor ถูกสืบทอดจากแม่สู่ลูกไหม?

Constructor จะไม่ถูกสืบทอดจากแม่สู่ลูก แต่ใน Constructor ของลูก จำเป็นต้องเรียก Constructor ตัวใดตัวหนึ่งของแม่

  • ถ้า Constructor ของลูกไม่เรียกใช้งาน Constructor ของแม่ บางภาษาโปรแกรมจะเรียก Default Constructor ของแม่ให้อัตโนมัติ
  • ถ้าลูกไม่มี Explicit Constructor บางภาษาโปรแกรมก็จะเรียก Default Constructor ของแม่ให้อัตโนมัติ
  • ถ้าลูกไม่มี Explicit Constructor และแม่ก็มีแต่ Parameterized constructor จะคอมไพล์ไม่ได้เลย เพราะไม่สามารถสร้าง object ได้

ตัวอย่าง Constructor ของคลาสที่มีการสืบทอด

class Rectangle{
public:
	int width;
	int height;
	Rectangle() :Rectangle(0, 0) {
	}
	Rectangle(int width, int height){
		this->width = width;
		this->height = height;
	}
};

class DrawableRectangle : public  Rectangle{
public:
	int x;
	int y;
	DrawableRectangle() : DrawableRectangle(0, 0, 0, 0){
	}
	DrawableRectangle(int width, int height) : 	DrawableRectangle(width, height, 0, 0){
	}
	DrawableRectangle(int width, int height,int x, int y) : Rectangle(width, height){
		this->x = x;
		this->y = y;
	}
};

จะเห็นว่า DrawableRectangle สืบทอดมาจาก Rectangle โดย DrawableRectangle จะมี Constructor 3 แบบ ซึ่งแบบที่ทำงานจริงจะรับ int 4 ตัว ซึ่งพอรับมาแล้วจะทำการเรียก Constructor ของ Rectangle แล้วก็กำหนดค่าให้ x และ y

‪#‎day25 #365วันแห่งโปรแกรม ‪#‎โครงการ365วันแห่ง‬...