Invoking an overloaded constructure using this keyword

ศศิพร โพธิ์ชะคุ้ม 650710582

การใช้คีย์เวิร์ด this เรียก constructor ที่ถูก overloaded ช่วยให้การจัดการและสร้างอ็อบเจ็กต์ภายในคลาสเดียวกันมีความยืดหยุ่นและมีประสิทธิภาพมากขึ้นทั้งลดความซับซ้อนในการทำซ้ำโค้ด ทำให้เข้าใจได้ง่ายยิ่งขึ้น

ข้อสำคัญของการใช้ this

  • คอนสตรัคเตอร์ที่ถูกเรียกด้วย this ต้องอยู่ใน class เดียวกันเสมอ

  • สามารถส่งพารามิเตอร์ให้กับคอนสตรัคเตอร์ที่ถูกเรียกได้

  • ชี้ไปที่สมาชิกของคลาสที่ถูกใช้งานอยู่เสมอ หรือก็คืออินสแตนซ์ของคลาสที่เราใช้งานในขณะนั้น

  • เป็นตัวบอก compiler ให้เรียกใช้ คอนสตรัคเตอร์เริ่มต้น(default constructor) หรือ constructor คอนสตรัคเตอร์ที่ไม่มีอาร์กิวเมนต์

การเรียกคอนสตรัคเตอร์ด้วย this

  • คอนสตรัคเตอร์สามารถเรียกใช้อีกคอนสตรัคเตอร์หนึ่งในออบเจ็กต์เดียวกันได้ โดยใช้คำสั่ง this ซึ่งสามารถใช้งานได้ทั้งคอนสตรัคเตอร์มีพารามิเตอร์และไม่มีพารามิเตอร์(default constructor)

  • พารามิเตอร์ในคอนสตรัคเตอร์จะสามารถใช้เป็นพารามิเตอร์สำหรับ this หรือใช้ในนิพจน์ (expression) ก็ได้

Syntax

class X 
{
   public X: this()
   {
      // โค้ด..
   }
}

ตัวอย่างโปรแกรม

ตัวอย่างที่ 1

// C# program to illustrate how to invoke
// overloaded constructor using this keyword
using System;
class Geek {

	// Constructor without parameter(default constructor)
	public Geek()
	{
		Console.WriteLine("Hello! Constructor 1");
	}

	// Constructor with parameter
	// Here this keyword is used 
	// to call Geek constructor
	public Geek(int a) 
	: this()
	{
		Console.WriteLine("Hello! Constructor 2");
	}
}

// Driver Class
public class GFG {

	// Main method
	static public void Main()
	{

		// Create object of Geek class
		Geek obj = new Geek(2);
	}
}

ในตัวอย่างนี้ จะเห็นได้ว่าคลาส Geek มีคอนสตรัคเตอร์ อยู่ 2 ตัว คือ

  1. Geek() ไม่มีพารามิเตอร์ โดยคอนสตรัคเตอร์นี้จะถูกเรียกเมื่อสร้างอ็อบเจ็กต์ Geek โดยไม่มีการส่งพารามิเตอร์เข้าไป

  2. Geek(int a) มีพารามิเตอร์ 1 ตัว คือ int aโดยคอนสตรัคเตอร์นี้มีการเรียกใช้ this() เพื่อเรียกคอนสตรัคเตอร์ที่ไม่มีพารามิเตอร์ก่อนที่จะทำงานในบล็อกนี้ ซึ่งจะทำให้ข้อความ "Hello! Constructor 1" ถูกพิมพ์ออกมาก่อน

ในคลาส CFG ซึ่งทำหน้าที่เป็น main ของโปรแกรม จะเห็นได้ว่า

เป็นการสร้างอ็อบเจ็กต์ที่เรียกคอนสตรัคเตอร์ที่มีพารามิเตอร์ นั่นคือ Geek(int a) จะถูกเรียกใช้ ซึ่งการที่จะมีการทำงานในส่วนของคอนสตรัคเตอร์นี้ จะมีการเรียกใช้คอนสตรัคเตอร์ที่ไม่มีพารามิเตอร์ นั่นคือ Geek() โดยการเรียกคอนสตรัคเตอร์นี้ผ่าน this() ซึ่งจะทำให้ "Hello! Constructor 1" ถูกพิมพ์ออกมา แล้วจึงจะทำงานในบล็อกของคอนสตรัคเตอร์ของตนเอง และพิมพ์ "Hello! Constructor 2"

output

Hello! Constructor 1
Hello! Constructor 2

ตัวอย่างที่ 2

public Employee(int weeklySalary, int numberOfWeeks)
    : this(weeklySalary * numberOfWeeks)
{
}
public Employee(int annualSalary)
{
    Salary = annualSalary;
}

จากตัวอย่างนี้ มีการใช้ this เรียกคอนสตรัคเตอร์ที่สอง โดยคอนสตรัคเตอร์แรก ที่มีพารามิเตอร์ 2 ตัว ได้แก่ int weeklySalary และ int numberOfWeeks ซึ่งในคอนสตรัคเตอร์ที่2มี พารามิเตอร์ 1 ตัว จะทำการรับ weeklySalary*numberOfWeeks เข้ามาเป็นค่าพารามิเตอร์ของตัวเองและเมื่อมีการสร้างออบเจ็กต์ในคลาส main

public class Example {

	// Main method
	static public void Main()
	{

		// Create object of Employee class
		Employee obj = new Employee(5000,4);
	}
}

เป็นการสร้างอ็อบเจ็กต์ที่เรียกคอนสตรัคเตอร์ที่มีพารามิเตอร์ นั่นคือ Employee(int weeklySalary, int numberOfWeeks) เมื่อทั้งสองรับค่าพารามิเตอร์ 5000 และ 4 เข้าไปแล้ว ก็จะทำการเรียกใช้ Employee(int annualSalary) โดยใช้ this ซึ่งมีการส่งพารามิเตอร์ไป 1 ตัวคือ ค่า weeklySalary*numberOfWeeks นั่นคือ 20000 ไปยังคอนสตรัคเตอร์ตตัวที่สอง ทำให้ Salary ในคอนสตรัคเตอร์ที่สอง มีค่าเป็น 20000

เปรียบเทียบกับ Python

สิ่งที่คล้ายกับการใช้คีย์เวิร์ด this ใน c#

  • การใช้ self จะคล้ายกับการใช้ this ในแง่ของการอ้างอิงถึง Instance ปัจจุบันของคลาส

  • การสร้างและการกำหนดค่าตอนสร้าง instance ซึ่งใน C# เราสามารถ overload constructor เพื่อเรียกใช้ constructure อื่น ในอีก constructure ที่อยู่ในคลาสเดียวกัน ซึ่งคล้ายกับการที่ Python มี __init__()ที่กำหนดค่าตอนสร้าง instance ซึ่งจะใช้วิธีจัดการกับพารามิเตอร์ใน __init__() โดยตรงแทนการ overload constructure

สิ่งที่แตกต่างกัน

  • Python ไม่มีการ overload constructor เหมือนใน C# แต่ใช้การจัดการพารามิเตอร์และเงื่อนไขใน __init__() เพื่อจำลองพฤติกรรมเดียวกันได้

  • การใช้ this ใน C# สามารถใช้เรียก constructor อื่นภายใน class เดียวกันได้ แต่ใน Python ใช้การสร้างเมธอดแยกออกมาต่างหาก หรือการจัดการค่าภายใน __init()__ แทน

ตัวอย่างการใช้ __init__()จำลองพฤติกรรมเดียวกัน

class Dog:
    def __init__(self, name, age=None):
        self.name = name
        if age is not None:
            self.age = age
        else:
            self.age = "Unknown"

    def __str__(self):
        return f"{self.name} is {self.age} years old"
        

#ทำการสร้างออบเจ็กต์และแสดงผล
>>> d1 = Dog("Fido", 5) # สร้างออบเจ็กต์ d1 ชื่อ "Fido" และอายุ 5
>>> print(d1)

>>> d2 = Dog("Buddy") # สร้างออบเจ็กต์ d2 ชื่อ "Buddy" และไม่กำหนดอายุ
>>> print(d2)

จากตัวอย่างจะเห็นได้ว่า __init__() เป็นเมธอดที่จะถูกเรียกใช้เมื่อมีการสร้างออบเจ็กต์ของคลาส Dog ซึ่งมีพารามิเตอร์ ได้แก่ self, name และ age โดยเรามีการกำหนดค่าเริ่มต้นของ age ไว้ให้เป็น None ทำให้สามารถสร้างอ็อบเจ็กต์ได้หลากหลายเช่นเดียวกับการ overload constructors ใน C# ซึ่งการใช้ default argument นี้ คล้ายกับการใช้ this ในC# ซึ่งเราสามารถปรับความยืดหยุ่นของการส่งพารามิเตอร์ตอนสร้างออบเจ็กต์ได้ ถ้าเรากำหนดต่า age ก็จะเก็บค่าที่เรากำหนดไว้ในฟิลด์ self.age ถ้าไม่กำหนด ก็จะเป็น Unknown

Output

Fido is 5 years old
Buddy is Unknown years old

เปรียบเทียบกับ Java

ใน Java เราสามารถใช้ this ได้เหมือนๆกันกับ C# โดยระหว่างการoverloading คอนสตรัคเตอร์ จะใช้ this ในการเรียกคอนสตรัคเตอร์ที่ไม่มีพารามิเตอร์ (default constructure) โดยอัตโนมัติจากคอนสตรัคเตอร์ที่มีพารามิเตอร์

ตัวอย่างการใช้ this เป็นอาร์กิวเมนต์ในคอนสตรัคเตอร์

// Java program to illustrate role of this() in
// Constructor Overloading
public class Box {
	double width, height, depth;
	int boxNo;

	// constructor used when all dimensions and
	// boxNo specified
	Box(double w, double h, double d, int num)
	{
		width = w;
		height = h;
		depth = d;
		boxNo = num;
	}

	// constructor used when no dimensions specified
	Box()
	{
		// an empty box
		width = height = depth = 0;
	}

	// constructor used when only boxNo specified
	Box(int num)
	{
		// this() is used for calling the default
		// constructor from parameterized constructor
		this();

		boxNo = num;
	}

	public static void main(String[] args)
	{
		// create box using only boxNo
		Box box1 = new Box(1);

		// getting initial width of box1
		System.out.println(box1.width);
	}
}

จากตัวอย่างจะเห็นได้ว่า

Class Box มี คอนสตรัคเตอร์อยู่ 3 ตัว

  • คอนสตรัคเตอร์ที่มีพารามิเตอร์ ได้แก่ Box(double w, double h, double d, int num) ใช้กำหนดความกว้าง, ความสูง, ความลึก, และหมายเลขกล่องทั้งหมด

  • คอนสตรัคเตอร์ที่ไม่มีพารามิเตอร์ ได้แก่ Box() ที่เป็นกล่องเปล่า (width, height และ dept มีค่าเป็น 0)

  • คอนสตรัคเตอร์ Box(int num) มีการเรียกใช้งานคอนสตรัคเตอร์ที่ไม่มีพารามิเตอร์ ด้วยคำสั่ง this() เพื่อให้ออบเจ็กต์ที่สร้างมีค่า width, height และ dept เป็น 0 ก่อนที่จะตั้งค่าหมายเลขกล่อง.

Main

  • ในส่วนของ main จะมีการสร้างอ็อบเจ็กต์ Box box1 = new Box(1); ซึ่งจะทำการเรียกคอนสตรัคเตอร์ที่มีพารามิเตอร์ 1 ตัว คือ Box(int num) ซึ่งใช้ this() เพื่อเรียกคอนสตรัคเตอร์ที่ไม่มีพารามิเตอร์ก่อน นั่นคือ Box() เพื่อให้แน่ใจว่าค่าต่างๆถูก set เป็นกล่องเปล่าเมื่อรันโปรแกรมก็จะได้ output ดังนี้

0.0

เปรียบเทียบกับภาษา C

ในภาษา C นั้นไม่มีแนวคิดของ constructor แบบเดียวกับที่มีใน C# เพราะภาษา C เป็นภาษาเชิงโครงสร้าง (procedural programming language) ซึ่งไม่ได้รองรับการเขียนโปรแกรมเชิงวัตถุ (OOP) โดยตรงแนวคิดเกี่ยวกับการเรียกใช้ overloaded constructor หรือการใช้ this จึงไม่มีอยู่ในภาษา C

เปรียบเทียบกับ C++

ใน C++ constructor delegation ช่วยให้ constructor หนึ่งสามารถเรียก constructor อื่นภายในคลาสเดียวกันได้ ซึ่งจะช่วยหลีกเลี่ยงการเขียนโค้ดซ้ำซ้อน ทำให้โค้ดสะอาดและดูแลรักษาง่ายขึ้น คล้ายกับการใช้ this ในการเรียก overloaded constructor

ตัวอย่างโปรแกรม

// Program to demonstrate constructor delegation
// in C++
#include <iostream>
using namespace std;
class A {
	int x, y, z;

public:
	A()
	{
		x = 0;
		y = 0;
		z = 0;
	}

	// Constructor delegation 
	A(int z) : A()
	{
		this->z = z; // Only update z
	}

	void show()
	{
		cout << x << '\n'
			<< y << '\n'
			<< z;
	}
};
int main()
{
	A obj(3);
	obj.show();
	return 0;
}

จากตัวอย่างจะเห็นได้ว่า คลาสนี้มีคอนสตรัคเตอร์อยู่สองตัว คือ Constructor A(): กำหนดค่าเริ่มต้นให้ตัวแปร x, y, และ z เป็น 0. และ Constructor ที่ใช้การ delegation A(int z) ซึ่งจะทำการเรียก A() ผ่านการใช้ : A() ก่อนที่จะทำการกำหนดค่า z ด้วยค่าที่ได้รับจากพารามิเตอร์

การทำงานของโปรแกรม

เมื่อเราเรียก A obj(3); จะทำการเรียก constructor ที่รับพารามิเตอร์ คือ A(int z) ซึ่ง constructor นี้จะเรียก A() ผ่านการใช้ : A() เพื่อกำหนดค่าเริ่มต้นให้ตัวแปร x, y, และ z เป็น 0 จากนั้นจึงจะอัพเดทค่าของ z เป็น 3 และเรียก obj.show(); แสดงค่าของ x, y, และ z

Output

0
0
3

Video

Presentation

อ้างอิง

Last updated