Polymorphisms สรุปง่ายๆว่าเป็นการอนุญาติให้ derived class ( child class ) สามารถใช้ function ของ parent ได้ สำหรับ polymorphisms นั้นเห็นเด่นชัดมากที่สุดก็คงจะเป็น Overriding / Overloading
Overriding
เป็นการเขียน function ของ Child class ใช้เองโดยไม่ต้องใช้ function ของ Parent Class ถ้าจะยกตัวอย่างง่ายๆ ก็เป็นต้นว่า ถ้าเรามี class ชื่อว่า Car แล้ว Car นั้นมีฟังชั่นขื่อว่า drive สมมติว่าเราจะเขียน class ใหม่ขึ้นมาโดยสืบทอด (inherit) มาจาก Car โดยชื่อว่า Tank มีฟังชั่นชื่อว่า drive เหมือนกัน แต่ว่า class ทั้งสองนั้น Drive ทำงานไม่เหมือนกัน คือพูดง่ายๆว่า รถยนต์ก็ ขับ(drive)ได้ รถถังก็ ขับ(drive) ได้ แต่วิธีการที่จะขับไม่เหมือนกัน
Overloading
เป็นการเขียน Function ชื่อเหมือนกัน ใน class เดียวกัน แต่รับ parameter คนละอย่างกัน เช่นว่า เรามี class ชื่อว่า Rectangle และมี function ในการคำนวนพื้นที่ เราอาจจะต้องการให้มันรับ parameter ได้ทั้ง int และ float ในลักษณะแบบนี้เราก็จะใช้ overloading เข้ามาให้เกิดประโยชน์
อาจจะงง เล็กน้อย สรุปสั้น Overriding ก็คือ child class ที่มีการเขียน function ที่ชื่อเหมือนกับ parent ขึ้นมาเองโดยไม่ต้องสืบทอดจาก parent และ Overloading คือ method ที่สามารถรับ parameter ได้หลายๆรูปแบบ
แต่มาดู code อาจจะเข้าใจง่ายกว่า
// Car.h
|
และในส่วน implement
|
เวลาเรียกใช้เราอาจจะเขียนได้ว่า
#import "car.h" |
ส่วนผลลัพธ์ที่ออกมาก็จะเป็น
Car driveCar drive at speed 80
ทีนี้เรามาดู Overriding กันบ้าง ก็อย่างที่บอกไปแล้วว่า เราสารมารถเขียน ให้ child class ทำงานต่างจาก parent โดยที่ ขื่อเหมือนกันได้มาดู กันเลยดีกว่า
// Tank.h |
แต่เราสารมารถเขียน implement ของตัวเองโดยอิงจาก parent ได้
#import "tank.h" @implementation Tank - (void) drive { printf ("Tank Driven"); } @end |
ก็เป็นอันเสร็จ คือเรา เขียน funtion drive ขึ้นมาใหม่ แทนที่ ตัวเก่าที่มีอยู่ใน Car
และก็มาลองเรียกใช้งานกันดู
#import "car.h" |
ส่วนผลลัพธ์ที่ได้ก็จะได้ว่า
Car drive
Tank drive
Car drive at speed 20
จากผลลัพธ์ก็จะเห็นว่า Tank drive ที่ออกมา โปรแกรมจะไปเรียก function ใน class Tank
ส่วนบรรทัดสุดท้าย ตัวโปรแกรมจะไปเรียกใช้ parent ของ tank นั่นก็คือ Car เพราะเนื่องจากว่า tank นั้น Overriding เพียงแค่ฟังชั่น
- (void) drive; |
แต่สำหรับ
- (void) drive:(int)speed; |
ไม่ได้ทำการ overriding
มันจึงไปใช้งาน parent ของมันแทน
Dynamic Binding
คือไม่รู้ว่าจะอธิบายง่ายๆได้อย่างไรว่ามันคืออะไร แต่เอาเป็นว่า ขอยกตัวอย่าง Dynamic Binding ให้เห็นภาพได้ว่า สมมติว่า เรามี class ชื่อว่า Dog และ Cat โดนทั้งสอง class นี้เป็น child ของ Animal และมี function ชื่อว่า eat เหมือนกัน ดู code ตัวอย่างภาษา C ต่อไปนี้
void function_eat(Animal *a) { a->eat(); } |
ถ้าสมมติว่า เราเรียก funciton_eat โดยส่ง pointer ของ Cat และ dog มาให้ในลักษณะแบบนี้
Cat *c = new Cat(); Dog *d = new Dog(); function_eat(c); function_eat(d); |
ะเห็นว่า เราสามารถส่ง ทั้ง Cat และ Dog ไปให้ function_eat ได้ เพราะว่าทั้ง Cat
และ Dog นั้นเป็น Animal ทั้งคู่ ปัญหาก็คือว่าโปรแกรมจะรู้ได้ยังไงว่าควรจะไปเรียก
eat ของ cat หรือว่าไปเรียก eat ของ dog
ตรงนี้ไม่ต้องกังวลเพราะว่าโปรแกรมจะไปตรวจสอบเองว่า Animal ที่ได้รับมาเป็น dog
หรือ cat กระบวนการที่โปรแกรมสามารถจำแนกได้ว่าเป็น class ใดนั้นเหละคือ Dynamic Binding
id Type
ในภาษา objective-c นั้นจะมีตัวแปรชนิดพิเศษที่ชื่อว่า id ตัวแปรชนิดนี้มันจะคล้ายๆลักษณะ pointer ในภาษา C แต่ id มันสามารถ เก็บค่าอะไรก็ได้ !!!
มาดูตัวอย่างอาจจะพอเห็นภาพมากกว่า
#import |
คือจาก code ข้างบน ประกาศ class ไว้คือ Human กับ Animal และทั้งสอง class นี้ก็ไม่ได้เกี่ยวกันแต่อย่างได
มาดูที่ main โปรแกรมจะเห็นว่า ประกาศ ตัวแปรมา 3 ตัวก็คือ both , h , a ซึ่งทั้งสามตัวแปรนี้เป็นคนละชนิดกัน จุดที่อยากให้รู้ก็คือว่า เราประกาศ both เป็น id สามารถเก็บอะไรก็ได้ และ
- เราก็ลองมาให้ both มีค่าเท่ากับ h หลังจากนั้นก็ลองเรียก printHuman
- เสร็จแล้ว ก็ให้ both มีค่าเท่ากับ a แล้วก็เรียก printAnimal
จะเห็นว่ามันสามารถสลับเปลี่ยนไปเป็น Human หรือ Animal และเรียก function ของทั้งสองได้ ผลลัพธ์ที่ได้ก็จะเป็นแบบนี้
Human
Animal
และการใช้งานลักษณะแบบนี้ก็เป็น dynamic binding นั่นเอง ก็อาจจะเกิดคำถามที่ว่า ก็ในเมื่อมันเก็บได้ทุกอย่าง เราก็ประกาศให้มันเป็น id หมดเลยก็ได้ คำตอบก็คือได้ แต่ไม่ควรทำ ด้วยหลายๆเหตุผล ขอยกตัวอย่างง่ายๆว่า
id a;กับ
Animal a;สองอย่างนี้ อะไรเข้าใจง่ายกว่า ว่า a คืออะไร?
ระหว่างบอกว่า a เป็น animal กับ a เป็น id ?
จริงๆมันก็มีอีกหลายๆเหตุผลที่ว่า เราควรใช้ในสิ่งที่จำเป็นมากกว่า ขอยกตัวอย่าง อีกสักอัน
สมมติว่าจาก code ตัวอย่างแรก เรามาแก้ให้เป็นแบบนี้
boht = human; [both printAnimal]; |
จะเห็นว่า เราให้ both นั้นเป็น human แต่เรากลับไปเรียกใช้ printAnimal
ซึ่งไม่มีใน Human แน่นอน … แต่เวลา Compile นั้นโปรแกรมจะไม่สามารถตรวจสอบได้ว่า
มันไม่มี printAnimal โปรแกรมจะสามารถ Compile ได้ปกติโดยไม่เกิด
error เพราะว่า dynamic binding นั้นจะเกิดขึ้นตอนโปรแกรมเริ่มทำงาน
ดังนั้นถ้าเราเรียกใช้โปรแกรมดังกล่าว ก็จะเกิด error
ทันที
และจะได้ผลลัพธ์ในลักษณะแบบนี้
Human
error: Animal (Instance)
Animal does not recognize printHuman
ฉนั้นการใช้ก็ควรจะระวังกันสักนิด
0 ความคิดเห็น:
แสดงความคิดเห็น