Tag Archives: Class

Objective-C Programmming :Extending Class

ปัญหาอย่างหนึ่งของการใช้ Framework หรือ Library ต่างๆก็คือ เราไม่อาจจะไปแก้ไขหรือเพ่ิมเติม method ต่างๆของ class ได้ เพราะว่าบางครั้ง Lib ที่ได้มานั้นก็มีแต่ lib ที่ผ่านการ compile เป็น binary files และมีแค่ header มาเท่านั้น วิธีการที่่เราจะเพิ่มเติมเข้าไปได้ก็คือ ต้องเขียน subclass ของ class นั้นๆ แต่ในภาษา Objective-C นั้นมีอีกวิธีหนึ่งที่เราสามารถเขียน method เพิ่มเติมเข้าไปยัง class เดิมได้ นั่นก็คือ category

สมมติว่าเราต้องการเขียน โปรแกรมที่ต้องการ reverse string บ่อยๆ เราอาจจะเขียน class ขึ้นมาใหม่และเขียน method ที่ชื่อว่า getReverse ขึ้นมา อาจจะเขียนได้ประมาณนี้ ได้ว่า

แล้วก็เขียน code ในส่วนของ getReverse ได้ว่า

เขียนแบบนี้ก็พอได้ แต่ว่ามันก็มีข้อเสียคือ เมื่อเราต้องการจะ reverse string เราต้องให้ตัวแปร ของเราเป็น ReverseString

ซึ่งมันไม่สะดวก วิธีที่ดีกว่านั้นก็อาจจะเขียนเป็น function ขึ้นมาเป็น  global ก็พอได้

แต่ถ้าหากเราอยากจะทำให้ NSMutableString มี method ที่ชื่อว่า getReverse เลยจะทำได้ไม๊ ?
คำตอบก็คือ ทำได้

Category นั้นทำให้เราสามารถที่จะเพิ่ม method ต่างๆเข้าไปยัง class ที่มีอยู่เดิมที่เราไม่สามารถจะไปแก้ไขในส่วนของ source ได้ แต่ Category ก็ไม่ได้สิทธิมากขนาดที่จะไปเพิ่ม member ใน Class ได้ เรามาลองดูการใช้ Category เลยอาจจะเข้าใจง่ายกว่า

จากตัวอย่างข้างบนนั้นถ้าหากเราต้องการจะเขียนให้  NSMutableString มี method นั้นเราก็ต้องเขียน category ขึ้นมาวิธีการ ก็สุดแสนจะง่ายดายเพียงแค่ โดยมีรูปแบบดังนี้

@interface ClassName ( CategoryName )

เอาละมาดูของจริงกันเลยดีกว่า ก่อนอื่นเราก็ประกาศ Category ที่ชื่อว่า MyExtend โดยเราจะเพิ่มเติมขยายในส่วนของ NSMutableString และเราก็เขียน method ใหม่ที่ชื่อว่า getReverse

หลังจากนั้นก็เขียน ในส่วนของ source ได้แบบนี้

เพียงแค่เท่านี้ก็เสร็จเรียบร้อย หลังจากนั้นแล้ว NSMutableString ของเราก็จะมี method ใหม่ที่ชื่อว่า getReverse เรียบร้อยแล้ว

การเรียกใช้ก็ไม่ได้ยาก ดังตัวอย่าง

และนอกจากนี้เรายังสามารถใช้ category เพื่อทำเป็น private method ได้ด้วย สมมติว่าเรามี Class ง่ายๆแบบนี้

และเขียน implement ง่ายๆแบบนี้

จะเห็นว่า AA นั้นมี getSomeInt ซึ่งเป็น public method และในกรณีที่เราอยากให้มันเป็น private เราอาจจะดัดแปลงได้โดยการใช้ category ได้แบบนี้

เป็นไงบ้างครับสำหรับการใช้ category จะเห็นว่ามันมีประโยชน์มากๆเลยสำหรับการขยายคลาส

Objective-C Programming Part IV

Super Self – Initializing

หลังจากเรื่องที่แล้วได้เขียนเกี่ยวกับ Polymorphism ถ้าจะไม่พูดถึง super – self ก็คงจะไม่ครบสักเท่าไหร่

  • super
    เป็น keyword ที่เอาไว้อ้างอิงถึง คลาสที่สืบทอดมา
  • self
    ก็คือเป็นการอ้างอิงถึงตัวเอง

เอาละทีนี้ก็คือว่า มันมีความสำคัญอะไรกับ 2 สิ่งนี้ สำหรับ self กับ super
จริงๆแล้ว self กับ super ส่วนมากจะได้ใช้จริงๆ กับ initial ซะส่วนมาก คือหลังจากการ alloc แล้วเราต้องทำการ init ให้มัน ทีนี้มันก็เกิดปัญหาที่ว่า ถ้าที่เราเขียน class ที่เป็น child จาก parent ที่ต้องการ initial ก่อนใช้งาน แล้วจะทำอย่างไร ?

ตัวอย่าง Code ข้างล่างจะไม่มีปัญหา เพราะว่า Child นั้นไม่ต้องการเขียน method ชื่อ init ดังนั้นก็ไปใช้ของ parent ได้

แบบนี้ก็อาจจะง่าย เวลาใช้งาน ก็อาจจะเขียนประมาณนี้

ก็ตอนนี้ก็เท่ากับว่า ค่า m_age นั้นมีค่าเท่ากับ 12

แต่ถ้าสมมติว่า initial ของ child ต้องการ parameter ด้วย เช่นว่า Children ก็ต้องการให้รับ age ตอน init
และ Student ก็ต้องการให้มี studentID ในตอน init ด้วยละ ดังเช่นตัวอย่าง

เราจะเขียน code ในลักษณะแบบนี้

มันก็จะไปเรียก init ของ child และในตอนนี้ m_studentID ก็มีค่าเท่ากับ 12.00 แล้ว m_age ละ ? เราจะทำการ set ค่า initial สำหรับ parent class ได้อย่างไร ?
เราจะรู้ได้อย่างไรว่า parent class นั้นมี member data อะไรอยู่ในนั้นบ้าง ?
เพราะในขณะนี้เรา overriding ไปแล้ว มันก็เป็นการเรียกใช้ init ของ child โดยไม่ได้เรียก init ของ parent

เพื่อความเข้าใจ ลองมาดูตัวอย่างอีกสักอันกันดีกว่า

แล้วเราก็เขียนในส่วนของ main แบบนี้

ผลจากการ โปรแกรมก็จะได้ว่า

Honda speed: 20

ความจริงแล้วจาก code ข้างบนถ้าทำการ compile มันก็จะไม่แจ้ง error อะไร แต่มันจะแจ้งwarning ออกมา ว่า warning: multiple methods named ‘-init’ found แต่จริงๆแล้วก็ทำงานได้ปกติ เหตุผลทีมันแจ้งแบบนี้ก็เพราะว่า init นั้นเป็น method ของ Object นั่นเอง และเราก็ทำการ Overriding มันไปนั่นเอง ทำให้มันเห็น ว่ามี init อยู่ 2 method

โอเคทีนี้สมมติว่าเรา อาจจะให้มี init กับ initWithSpeed ละ ? ตัวแรกไม่ต้องทำอะไร ส่วนตัวที่สอง ทำการ ใส่ speed เริ่มต้นให้เลย จะเขียนได้แบบไหน เราก็ได้ความคิดว่า งั้น init ก็ไม่ต้องไป Overriding ให้มัน แล้วเราก็เขียน initWithSpeed เพิ่มขึ้นมานั่นเอง โอเค งั้นมาดูเลย

จะเห็นว่า เราก็แค่ เปลี่ยนจาก init ไปเป็น initWithSpeed เท่านั้นเอง งั้นส่วนของ implement นั้นก็ควรจะเป็น

แบบนี้ก็เป็นอันจบ แล้วส่วน main ก็น่าจะเขียนแบบนี้

แต่ความเป็นจริงแล้ว มันไม่ได้ง่ายขนาดนั้น !!!!

ถ้า compile จริงๆมันจะเกิด error ขึ้น เพราะว่า  initWithSpeed นั้น return void  โอเค เราจะแก้ปัญหานี้ได้โดยการเขียน code ใน main แบบนี้

แต่ความจริงแล้ว การแก้ปัญหาแบบนี้มันไม่ค่อยถูกเท่าไหร่ เพราะว่าถ้าจะพิจารณาให้ดีแล้ว มันเหมือนกับเราเขียนว่า initWithSpeed เป็นแค่ function ที่่เรียกใช้หลักจากการสร้าง honda แล้วมากกว่า ถ้าจะสรุปง่ายก็คือว่าการเขียนแบบข้างบน ก็เหมือนกับ การเขียนแบบนี้

เอาละ งั้นเราจะเขียนให้มันใช้ initWithSpeed ร่วมกับ alloc ได้ยังไง

ไม่ยากเลย  เราก็ให้ initWithSpeed ไม่ต้อง return void ให้มัน return Car ออกแทนสิ แต่จะให้มัน return ได้ยังไง นี่คือปัญหา  และ self กับ super จะได้เอามาใช้ตอนนี้เหละ งั้นก็ดูกันเลย

เราทำการเปลี่ยน ในส่วนของ interface ก่อน

โดยเราทำการเปลี่ยนให้ initWithSpeed ทำการ return id ออกมาแทน

และในส่วนของ implementation นั้น จะเขียนได้แบบนี้

จะเห็นว่า เราทำการ เรียกใช้ super และ self

  • [super init]
    ในส่วนนี้เป็นการบอกว่า ให้ เรียกใช้ Class แม่ (super) และทำการ เรียกใช้ init เพราะว่า จริงๆแล้ว Car นั้นสืบทอดมาจาก Object และ init นั้นก็เป็น method ที่เรียกใช้เวลา ทำการ  alloc ตัว object ก็เป็นอันว่า เราได้ทำการ init เรียบร้อยแล้ว ต่อไปก็
  • m_speed = speed
    ตรงนีก็ไม่ได้มีอะไรพิเศษนอกจากทำการ ใส่ค่าให้กับตัวแปร m_speed
  • return self
    ตรงนี้สำคัญเพราะเมื่อเราทำการ initตัวแม่แล้ว และเราก็ทำการ ใส่ค่าให้กับตัวแปรที่ต้องการแล้ว แน่นอนว่า การ alloc นั้น ต้องการขอจอง memory สำหรับตัวมันเอง ไม่ใช่ตัวแม่ ดังนั้นเราก็ return ตัวมันเองออกไป

และทีนี้เราก็จะเขียน main โปรแกรมได้ใหม่ว่า

แบบนี้ก็จะไม่เกิด error หรือ warning ใดๆ เลย และถ้าไม่อยาก initWithSpeed ก็ทำได้เหมือนกัน

ผลจากการ run โปรแกรมก็จะออกมาได้ว่า

Honda speed: 50
Toyota speed: 0

ลองโหลด source ไปลองดูได้ครับ

Objective-C Programming Part III.

Polymorphisms

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 อาจจะเข้าใจง่ายกว่า

และในส่วน implement

จากตัวอย่างข้างบนเป็นการ แสดงให้เห็นถึง Overloading คือ จะเห็นว่า Car นั้นมี Function ชื่อเหมือนกัน นั่นคือ drive แต่รับ parameter มาไม่เหมือนกัน โดยที่ drive แรกนั้น ไม่ได้รับ parameter มาเลย ส่วนตัวที่สอง รับ int เข้ามาและ ก็ในส่วนการทำงานของแต่ละฟังชั่นก็ต่างกัน

เวลาเรียกใช้เราอาจจะเขียนได้ว่า

ส่วนผลลัพธ์ที่ออกมาก็จะเป็น

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

ก็จะเห็นว่าใน class tank นั้นไม่มีอะไรเลย คือ inherit มาจาก car อย่างเดียว แต่เราสารมารถเขียน implement ของตัวเองโดยอิงจาก parent ได้

ก็เป็นอันเสร็จ คือเรา เขียน funtion drive ขึ้นมาใหม่ แทนที่ ตัวเก่าที่มีอยู่ใน Car

และก็มาลองเรียกใช้งานกันดู

ส่วนผลลัพธ์ที่ได้ก็จะได้ว่า

จากผลลัพธ์ก็จะเห็นว่า Tank drive ที่ออกมา โปรแกรมจะไปเรียก function ใน class Tank

ส่วนบรรทัดสุดท้าย ตัวโปรแกรมจะไปเรียกใช้ parent ของ tank นั่นก็คือ Car เพราะเนื่องจากว่า tank นั้น Overriding เพียงแค่ฟังชั่น

แต่สำหรับ

ไม่ได้ทำการ overriding

มันจึงไปใช้งาน parent ของมันแทน

เพิ่มเติม http://gd.tuwien.ac.at/languages/c/c++oop-pmueller/
และ http://developer.apple.com/documentation/Cocoa/Conceptual/OOP_ObjC/Introduction/chapter_1_section_1.html

Pure Virtual

คือจาก เมื่อวันที่ผ่านมา เนื่องจากว่า งานที่ทำอยู่มีส่วนต้องให้ port โปรแกรมจาก Win มาสู่ mac และบังเอิญว่า ผม compile แล้วมันผ่าน แต่ว่าตอน Runtime มันดัน Error สิ่งที่มันบอกมาก็คือว่า pure virtual method called terminated called with out an active exception ปัญหาที่เกิดขึ้น ก็ยัง งงๆๆว่าเป็นเพราะอะไร แต่พอหลังจากให้เพื่อนมาดูแล้วก็นั่งถกกัน ว่ามันเกิด เฉพาะกับ mac หรือเปล่าเพราะว่าใน win ไม่เห็นมันจะเกิด ก็เลยทำการเขียน code ที่ทำงานแบบเดียวกัน ก็ัดังตัวอย่างข้างล่าง

ก็ถ้า ดูตาม code ก็จะเห็นว่า มี Base กับ Derived เนื่องจากว่า Base Class มันเป็น Pure Virtual (Abtract Class) เราต้อง implement ส่วนของ code การทำงานใน derived class เสมอไม่อาจจะเขียน implement ใน Base Class ได้ และปัญหาจากโปรแกรมข้างบนเกิดขึ้นเพราะในขณะที่ base class ได้เรียก destructor ของตัวเองนั้น มันกลับไปเรียกใช้งานฟังชั่นใน derived class ด้วย ซึ่งนั่นก็ทำให้มันเกิด error เพราะว่า derived class ได้ถูกทำลายไปก่อนแล้ว ทำให้ไม่สามารถเรียกได้

ลองดูตรง

จาก destructor นี้จะเห็นว่า มีการเรียกฟังก์ชั่น foo และแน่นอนว่า foo ไปเรียก

อีกที สืบเนื่องจากว่ามันเป็น pure virtual แปลว่าตัว Base Class เองไม่อาจจะเขียน implement code ได้มันจึงต้องไปเรียก banana ในตัว Derived Class ที่มีการเขียน implement code และ Derived นั้นได้ทำลายจาก destructor ไปเรียบร้อยแล้ว มันเลยไม่เจอ banana ทำให้เกิด error นั่นเอง

ลองศึกษา เพิ่มเติมเกี่ยวกับ Virtual Function ได้ที่ http://en.wikipedia.org/wiki/Virtual_function

Objective-C Programming II : More about Class – Inheritance

สำหรับหัวข้อนี้จะกล่าวถึงรายละเอียดต่างๆเกี่ยวกับ Inheritance (การสืบทอด) ว่ามันคืออะไรและมีความสำคัญยังไง ตั้งแต่พื้นๆก่อนเลยละกัน ก่อนอื่นมาทำความเข้าใจ ของความหมาย ของคำว่า

  • Root class
    ความหมายของ root คือ class ที่ไม่มี parent หรือหมายความง่ายๆว่ามันไม่ได้ไปสืบทอดใคร
  • Parent class
    ส่วน parent นั้นก็คือ class ที่เป็นต้นแบบของ class อื่นๆ และตัว parent เองก็อาจจะสืบทอดคนอื่น(child) มาอีกทีก็ได้
  • Child class
    เป็นการเรียก class ที่สืบทอดมาจากคนอื่น

เพื่อความเข้าใจง่ายๆ ยกตัวอย่าง เรื่องของสัตว์มาประกอบ ก็แล้วกันน่ะสัตว์ทั้งหมดในโลก ขอเรียกว่า เป็น Animal ทั้งหมดเลยแล้วกัน แล้วสัตว์ต่างๆ ก็อาจจะแบ่งออกได้เป็น Mammal ( สัตว์เลี้ยงลูกด้วยนม ) และ Fish ( ปลา ) และ ถ้าในบรรดาเหล่า Mammal ก็มี Dog ซึ่งเป็นสัตว์ชนิดหนึ่งเหมือนกัน
เพื่อความเข้าใจง่ายๆ ดูภาพประกอบ

อธิบายตามภาพ

  • Animal เป็น Root Class
  • คลาสที่ต่อออกมาจาก animal ก็คือ mammal ( สัตว์เลี้ยงลูกด้วยนม ) ดังนั้น parent class ของ mammal ก็คือ Animal
  • Fish เป็น class ที่สืบทอดมากจา animal พูดง่ายๆว่าเป็น child ของ animal และก็แน่นอนว่า Fish มี parent class คือ animal เช่นเดียวกัน
  • และสุดท้าย mammal มี child class ที่ชื่อว่า dog และในทางกลับกัน dog ก็จะมี parent class เป็น Mammal

ถ้าหากเราให้คุณสมบัติของ class ต่างๆ เช่นว่า

  • animal เป็นสิ่งมีชีวิตที่ต้องกินอาหาร
  • mammal เลี้ยงลูกด้วยนม
  • fish หายใจในน้ำได้

นั่นก็แปลได้ว่า dog นั้นเป็นสิ่งมีชีวิตที่ต้องกินอาหาร ( สืบทอดจาก animal ) และเป็นสัตว์เลี้ยงลูกด้วยนม ( สืบทอดจาก mammal ) แต่ไม่อาจจะหายใจในน้ำได้เพราะไม่ได้สืบทอดมาจาก Fish

เราลองมาเขียน class จากแผนภาพในแบบง่ายๆกัน

จาก code ข้างบน ประกาศ class ชื่อว่า animal โดยมี ตัวแปรเป็น string เอาไว้เก็บชื่อของสัตว์ตัวนี้ และสัตว์ต่างๆก็ต้องการ การกินอาหาร เลยประกาศ method ชื่อว่า eat ขึ้นมา

แล้วก็ประกาศ class ชื่อว่า mammal ขึ้นมา โดยสืบทอดมาจาก animal และก็เพิ่ม method ชื่อว่า feedMilk เข้าไป จากตรงนี้ Mammal ก็จะสามารถเรียกใช้ method ของ animal ได้ด้วย นั่นก็คือ eat นั่นเอง และส่วนตัวของ mammal เองก็มี method ของตัวเองที่ชื่อ feedMilk ด้วย

สุดท้ายที่เราประกาศก็คือ dog โดยเพิ่ม method เข้ามาอีกสองอันนั่นก็คือ bite กับ run

สรุปได้ว่า ตอนนี้ dog นั้นสามารถ eat , feedMilk , bite , run ทำได้ทั้ง 4 อย่างเลย
จะเห็นได้ว่า inheritance นั้นมีประโยชน์มาก เพราะว่าเราสามารถ สร้าง class ใหม่ขึ้นมาได้ จาก class ที่มีอยู่แล้ว ทำให้เราลดเวลาการเขียนโปรแกรมลงได้ได้เยอะมาก และเป็นส่วนสำคัญสำหรับ การเขียนโปรแกรมในแบบ OOP ( Object Oriented Programming )