1 Chương 6 Đa hình Cao Tuấn Dũng Huỳnh Quyết Thắng Bộ môn CNPM TS H Q Thắng TS C T Dũng CNPM 2 Khái niệm đa hình "Trong lập trình đối tượng đa hình là khả năng các đối tượng khác nhau có thể trả lời[.]
Chương 6: Đa hình Cao Tuấn Dũng Huỳnh Quyết Thắng Bộ mơn CNPM Khái niệm đa hình "Trong lập trình đối tượng đa hình khả đối tượng khác trả lời thơng điệp theo cách riêng chúng" Khả đối tượng lớp khác đáp ứng thực hàm khác lớp khác cho giao diện gọi hàm TS H.Q Thắng - TS C.T Dũng CNPM Overloading Overriding Đa hình liên quan đến khái niệm: method overriding (định nghĩa lại phương thức) – “override” có nghĩa “vượt quyền” Method overriding: phương thức lớp sở định nghĩa lại lớp dẫn xuất định nghĩa lớp sở bị “che” định nghĩa lớp dẫn xuất Với method overriding, tồn thơng điệp (cả tên tham số) hoàn toàn giống - điểm khác lớp đối tượng nhận thông điệp TS H.Q Thắng - TS C.T Dũng CNPM Overloading vs Overriding Function overloading - Hàm chồng: dùng tên hàm cho nhiều định nghĩa hàm, khác danh sách tham số Method overloading – Phương thức chồng: tương tự void jump(int howHigh); void jump(int howHigh, int howFar); – hai phương thức jump trùng tên có danh sách tham số khác Tuy nhiên, khơng phải đa hình hướng đối tượng mà ta định nghĩa, thực hai thông điệp jump khác TS H.Q Thắng - TS C.T Dũng CNPM Method Overriding Xét hành vi “draw” lớp phả hệ bên – thông điệp “draw” gửi cho thể lớp yêu cầu thể tự vẽ – thể Point phải vẽ điểm, thể Circle phải vẽ đường tròn, thể Rectangle phải vẽ hình chữ nhật TS H.Q Thắng - TS C.T Dũng CNPM Định nghĩa lại phương thức Để override phương thức lớp sở, phương thức lớp dẫn xuất phải có tên, danh sách tham số, kiểu giá trị trả về, const không const Nếu lớp sở có nhiều phiên overload phương thức, việc override phương thức che tất phương thức cịn lại TS H.Q Thắng - TS C.T Dũng CNPM Định nghĩa lại hành vi Draw (C++) class Point { public: Point(int x, int y, string color); ~Point(); void draw(); private: int x; int y; string color; }; class Circle : public Point { public: Circle (int x, int y, string color, int radius); ~Circle(); void draw(); private: Khai báo lại lớp kế thừa int radius; }; void Point::draw() { // Draw a point } void Circle::draw() { // Draw a circle } Cung cấp định nghĩa TS H.Q Thắng - TS C.T Dũng CNPM Định nghĩa lại Draw() Kết quả: tạo thể lớp khác gửi thơng điệp “draw”, phương thức thích hợp gọi Point p(0,0,”white”); Circle c(100,100,”blue”,50); p.draw(); // Vẽ điểm Trắng (0,0) c.draw(); // Vẽ hình trịn xanh dương bán kính 50 (100,100) Ta tương tác với thể lớp dẫn xuất thể chúng thể lớp sở Circle *pc = new Circle(100,100,”blue”,50); Point* pp = pc; Nhưng có đa hình, lời gọi sau làm gì? pp->draw(); // Draw what??? TS H.Q Thắng - TS C.T Dũng CNPM Ví dụ đa hình: Bị điên Một bò – Kêu Moo TS H.Q Thắng - TS C.T Dũng CNPM Bò điên Bò điên – bị: tưởng ếch kêu oap TS H.Q Thắng - TS C.T Dũng CNPM 10 Bò điên Như vậy, tạo đối tượng Cow, gọi hành vi makeASound() nó, kêu “moo” Cow bob(“Bob”, “brown”); bob.makeASound(); Ta tạo trỏ tới đối tượng Cow, làm cho kêu “moo” p_bob = &bob; p_bob->makeASound(); TS H.Q Thắng - TS C.T Dũng CNPM 11 Nhập nhằng Nếu coi bị điên (MadCow), hành động bò điên MadCow maddy(“Maddy”, “white”); maddy.makeASound(); // Go “oap” MadCow * maddy = new MadCow(“Maddy”, “white”); maddy->makeASound(); // Go “oap” Cịn tưởng bị thường (Cow), lại bình thường MadCow* maddy = new madCow(“Maddy”, “white”); Cow* cow = maddy; // Upcasting cow->makeASound(); // Go “moo” ??? Làm để bò điên lúc điên (kêu “oap”)? TS H.Q Thắng - TS C.T Dũng CNPM 12 Liên kết lời gọi hàm function call binding Function call binding quy trình xác định khối mã hàm cần chạy lời gọi hàm thực C: đơn giản hàm có tên C++: chồng hàm, phân tích chữ ký kiểm tra danh sách tham số TS H.Q Thắng - TS C.T Dũng CNPM 13 Ngôn ngữ HĐT method call binding Liên kết lời gọi phương thức Đối với lớp độc lập (không thuộc thừa kế nào), quy trình gần khơng khác với function call binding – so sánh tên phương thức, danh sách tham số để tìm định nghĩa tương ứng – số tham số tham số ẩn: trỏ this TS H.Q Thắng - TS C.T Dũng CNPM 14 Liên kết tĩnh C/C++ function call binding, C++ method binding ví dụ static function call binding Static function call binding (hoặc static binding – liên kết tĩnh) quy trình liên kết lời gọi hàm với định nghĩa hàm thời điểm biên dịch – gọi “compile-time binding” – liên kết biên dịch, “early binding” – liên kết sớm TS H.Q Thắng - TS C.T Dũng CNPM 15 Liên kết tĩnh: trường hợp có thừa kế Kiểu tĩnh: MadCow Kiểu tĩnh: Cow Cow bob(“Bob”,”brow”); MadCow maddy(“Maddy”, “white”); bob.makeASound(); // go “moo” maddy.makeASound(); // go “oap” MadCow& rMaddy = maddy; rMaddy.makeASound(); // Go “oap” MadCow* pMaddy = &maddy; pMaddy->makeASound(); // Go “oap” Cow& rCow = maddy; rCow.makeASound(); // Go “moo” Cow* pCow = &maddy; pCow->makeASound(); // Go “moo” TS H.Q Thắng - TS C.T Dũng CNPM Sao không kêu oap??? 16 Liên kết tĩnh Với liên kết tĩnh, định “định nghĩa hàm chạy” đưa thời điểm biên dịch - lâu trước chương trình chạy thích hợp cho lời gọi hàm thông thường – lời gọi hàm xác định định nghĩa hàm, kể trường hợp hàm chồng phù hợp với lớp độc lập không thuộc thừa kế – lời gọi phương thức từ đối tượng lớp hay từ trỏ đến đối tượng xác định phương thức TS H.Q Thắng - TS C.T Dũng CNPM 17 Đa hình tĩnh Đa hình tĩnh thích hợp cho phương thức: – định nghĩa lớp, gọi từ thể lớp (trực tiếp gián tiếp qua trỏ) – định nghĩa lớp sở thừa kế public không bị override lớp dẫn xuất, gọi từ thể lớp dẫn xuất trực tiếp gián tiếp qua trỏ tới lớp dẫn xuất qua trỏ tới lớp sở – định nghĩa lớp sở thừa kế public bị override lớp dẫn xuất, gọi từ thể lớp dẫn xuất (trực tiếp gián tiếp qua trỏ tới lớp dẫn xuất) TS H.Q Thắng - TS C.T Dũng CNPM 18 Đa hình động Dynamic function call binding (dynamic binding – liên kết động) quy trình liên kết lời gọi hàm với định nghĩa hàm thời gian chạy Với liên kết động, định chạy định nghĩa hàm đưa thời gian chạy, ta biết trỏ trỏ đến đối tượng thuộc lớp – gọi “run-time” binding “late binding” Đa hình động (dynamic polymorphisme) loại đa hình cài đặt liên kết động TS H.Q Thắng - TS C.T Dũng CNPM 19 Hàm ảo Hàm/phương thức ảo – virtual function/method chế C++ cho phép cài đặt đa hình động Nếu khai báo hàm thành viên (phương thức) virtual, trình biên dịch đẩy lùi việc liên kết lời gọi phương thức với định nghĩa hàm chương trình chạy – nghĩa là, ta bảo trình biên dịch sử dụng liên kết động thay cho liên kết tĩnh phương thức Để phương thức liên kết thời gian chạy, phải khai báo phương thức ảo (từ khoá virtual) lớp sở TS H.Q Thắng - TS C.T Dũng CNPM 20 10 Quay lại ví dụ Bị điên TS H.Q Thắng - TS C.T Dũng CNPM 21 Hàm ảo Khai báo với từ khoá virtual định nghĩa lớp Không cần định nghĩa hàm, định nghĩa hàm nằm định nghĩa lớp Một phương thức khai báolà hàm ảo lớp sở, tự động hàm ảo lớp dẫn xuất trực tiếp gián tiếp TS H.Q Thắng - TS C.T Dũng CNPM 22 11 Điều kiện để thực đa hình C++ Tồn kế thừa lớp theo sơ đồ phân cấp Các lớp sơ đồ phân cấp phải có hàm khai báo với từ khố virtual – phải có hàm thành phần virtual Để duyệt phân cấp phải khai báo sử dụng trỏ reference đến lớp sở Con trỏ reference sử dụng để gọi hàm thành phần ảo TS H.Q Thắng - TS C.T Dũng CNPM 23 Constructor Destructor ảo Khơng thể khai báo constructor ảo Có thể (và nên) khai báo destructor hàm ảo class A { public: A() { cout