1. Trang chủ
  2. » Công Nghệ Thông Tin

Lập trình hướng đối tượng - Chương 9 doc

27 240 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Cấu trúc

  • I/ Con trỏ và Lớp dẫn xuất

    • IV/ p dụng đa hình

Nội dung

Chương 9 Tính đa hình • Con trỏ và Lớp dẫn xuất • Dẫn nhập các hàm ảo • Các hàm ảo thuần túy • Áp dụng đa hình Chương 9 Tính đa hình 270 I/ Con trỏ và Lớp dẫn xuất 1/ Khái niệm Tính đa hình (polymorphism) được hổ trợ bằng hai cách khác nhau trong C++ . Cách 1, đa hình được hổ trợ khi biên dòch chương trình (compiler) thông qua việc quá tải các hàm và toán tử . Cách 2, đa hình được hổ trợ ở thời điểm thực thi chương trình (run-time) thông qua các hàm ảo . Cách này giúp lập trình viên linh động hơn. • Cơ sở của hàm ảo và đa hình khi thực thi chương trình là các con trỏ của lớp dẫn xuất. Chương 3 có khảo sát về con trỏ, một đặc tính mới của con trỏ sẽ được khảo sát trong chương này. Nếu p là một con trỏ tới lớp cơ sở, thì có thể sử dụng p để trỏ tới bất kỳ lớp nào được suy ra từ lớp cơ sở . Chẳng hạn, có hai lớp cơ sở base và lớp dẫn xuất derived kế thừa base, các phát biểu sau đều đúng base *p; // base class pointer base base_ob; // object of type base derived derived_ob; // object of type derived // p can, of course, point to base objects p = & base_ob; // p points to base object // p can also point to derived objects without error p = & derived_ob; // p points to derived object Một con trỏ của lớp cơ sở có thể trỏ tới bất kỳ lớp dẫn xuất nào của lớp cơ sở mà không gây ra báo lỗi khác kiểu . Song chỉ có thể truy cập được các thành phần mà lớp dẫn xuất được kế thừa từ lớp cơ sở . Bởi vì con trỏ của lớp cơ sở chỉ biết lớp cơ sở mà thôi, nó không biết gì những thành phần được thêm vào bởi lớp dẫn xuất. Chương 9 Tính đa hình 271 • Một con trỏ của lớp dẫn xuất không thể dùng để truy cập một đối tượng của lớp cơ sở . (Việc sử dụng linh hoạt kiểu có thể dùng để khắc phục hạn chế nói trên, nhưng nó không được khuyến khích sử dụng) Các phép toán số học trên con trỏ liên quan đến kiểu dữ liệu mà con trỏ đó được khai báo để trỏ đến. Do đó, nếu con trỏ đến một đối tượng lớp dẫn xuất, rồi tăng nội dung con trỏ lên 1 . Điều này không làm cho con trỏ chỉ đến đối tượng mới của lớp dẫn xuất, mà nó sẽ chỉ đến đối tượng mới của lớp cơ sở . Ví dụ 1.1 Dùng con trỏ của lớp cơ sở để truy cập đến lớp dẫn xuất. // Demonstrate pointer to derived class. #include <iostream.h> class base { int x; public: void setx(int i) { x = i; } int getx() { return x; } }; class derived : public base { int y; public: void sety(int i) { y = i; } int gety() { return y; } }; int main() { base *p; // pointer to base type base b_ob; // object of base derived d_ob; // object of derived // use p to access base object p = &b_ob ; Chương 9 Tính đa hình 272 p->setx(10); // access base object cout << "Base object x: " << p->getx() << '\n'; // use p to access derived object p = &d_ob ; // point to derived object p->setx(99); // access derived object // can't use p to set y, so do it directly d_ob.sety(88); cout << "Derived object x: " << p->getx() << '\n'; cout << "Derived object y: " << d_ob.gety() << '\n'; return 0; } II/ Dẫn nhập hàm ảo (virtual function) 1/ Khái niệm Hàm ảo là hàm thành phần của một lớp, nó được khai báo ở lớp cơ sở và được đònh nghiã lại trong lớp dẫn xuất. Khai báo hàm ảo bắt đầu bằng từ khoá virtual . Một lớp có chứa hàm ảo được kế thừa, lớp dẫn xuất sẽ tái đònh nghiã hàm ảo đó cho chính mình. • Các hàm ảo triển khai ý tưởng chủ đạo của đa hình là " một giao diện cho nhiều phương thức ". Hàm ảo bên trong một lớp cơ sở đònh nghiã hình thức giao tiếp đối với hàm đó. Việc tái đònh của hàm ảo ở lớp dẫn xuất là thi hành các tác vụ của hàm liên quan đến chính lớp dẫn xuất đó . Nói cách khác, tái đònh các hàm ảo chính là tạo ra các phương thức cụ thể. Hàm ảo tái đònh ở lớp dẫn xuất không cần sử dụng từ khoá virtual. • Nguyên lý làm việc của đa hình trong khi thực thi chương trình : Chương 9 Tính đa hình 273 Hàm ảo được gọi thực thi giống như các hàm thành phần bình thường của lớp. Tuy nhiên, khi gọi hàm ảo bằng con trỏ, việc hổ trợ tính đa hình trong khi thực thi chương trình sẽ xảy ra. Khi một con trỏ trỏ đến một lớp dẫn xuất có chứa hàm ảo và hàm ảo này được gọi bằng con trỏ thì trình biên dòch sẽ xác đònh phiên bản nào của hàm đó sẽ được thực thi. Do đó nếu có hai hay nhiều lớp dẫn xuất của một lớp cơ sở nào đó, và chúng đều có chứa hàm ảo, thì con trỏ của lớp cơ sở có thể trỏ đến các đối tượng khác nhau của lớp dẫn xuất nói trên, tức là có thể gọi đến nhiều phiên bản khác nhau của các hàm ảo. • Một lớp có chứa hàm ảo được gọi là lớp đa hình . Ví dụ 2.1 // A simple example using a virtual function. #include <iostream.h> class base { public: int i; base(int x) { i = x; } virtual void func() { cout << "Using base version of func(): "; cout << i << '\n'; } }; class derived1 : public base { public: derived1(int x) : base(x) {} void func() { cout << "Using derived1's version of func(): "; cout << i * i << '\n'; } Chương 9 Tính đa hình 274 }; class derived2 : public base { public: derived2(int x) : base(x) {} void func() { cout << "Using derived2's version of func(): "; cout << i + i << '\n'; } }; int main() { base *p; base ob(10); derived1 d_ob1(10); derived2 d_ob2(10); p = &ob; p->func() ; // use base's func() p = &d_ob1; p->func() ; // use derived1's func() p = &d_ob2; p->func() ; // use derived2's func() return 0; } @ Kiểu của đối tượng được trỏ đến sẽ xác đònh phiên bản nào của hàm ảo được thực thi thông qua cách gọi hàm bằng con trỏ. Điều này chỉ xác đònh được trong lúc run- time. 2/ Hàm ảo và quá tải hàm Giải thích kết qủa chương trình ? Using base version of func() : 10 Using derived1's version of func() : 100 Using derived2's version of func() : 20 Chương 9 Tính đa hình 275 Việc tái đònh hàm ảo trong một lớp dẫn xuất có tương tự như quá tải hàm không ? Câu trả lời là không. Quá tải hàm Hàm ảo Số lượng đối số Cho phép khác biệt Phải giống nhau Kiểu dữ liệu của đối số Cho phép khác biệt Phải giống nhau Hàm thành phần của lớp Không bắt buộc Bắt buộc Hàm tạo Được phép Không được Hàm hủy Không được Có thể Vò trí Việc tái đònh hàm ảo trong một lớp dẫn xuất còn được gọi là gán thứ tự ưu tiên cao hơn cho hàm đó . 3/ Các hàm ảo được phân cấp theo thứ tự kế thừa . Nếu lớp dẫn xuất không tái đònh hàm ảo nào đó thì lớp này sẽ sử dụng phiên bản hàm của lớp cơ sở. Ví dụ 2.2 // Virtual functions are hierarchical. #include <iostream.h> class base { public: int i; base(int x) { i = x; } virtual void func() { cout << "Using base version of func(): "; cout << i << '\n'; } }; class derived1 : public base { public: derived1(int x) : base(x) {} void func() Chương 9 Tính đa hình 276 { cout << "Using derived1's version of func(): "; cout << i*i << '\n'; } }; class derived2 : public base { public: derived2(int x) : base(x) {} // derived2 does not override func() }; int main() { base *p; base ob(10); derived1 d_ob1(10); derived2 d_ob2(10); p = &ob; p->func() ; // use base's func() p = &d_ob1; p->func(); // use derived1's func() p = &d_ob2; p->func() ; // use base's func() return 0; } 4/ Cách đáp ứng của hàm ảo đối với một biến cố ngẫu nhiên ở thời điểm run- time Ví dụ 2.3 // This example illustrates how a virtual function can be used to respond to random // events occurring at run time. Kết qủa chương trình Using base version of func() : 10 Using derived1's version of func() : 100 Using base version of func() : 10 Chöông 9 Tính ña hình 277 #include <iostream.h> #include <stdlib.h> class base { public: int i; base(int x) { i = x; } virtual void func() { cout << "Using base version of func(): "; cout << i << '\n'; } }; class derived1 : public base { public: derived1(int x) : base(x) {} void func() { cout << "Using derived1's version of func(): "; cout << i*i << '\n'; } }; class derived2 : public base { public: derived2(int x) : base(x) {} void func() { cout << "Using derived2's version of func(): "; cout << i+i << '\n'; } }; int main() Chương 9 Tính đa hình 278 { base *p; derived1 d_ob1(10); derived2 d_ob2(10); int i, j; for(i=0; i<10; i++) { j = rand(); if( ( j % 2) ) p = &d_ob1; // if odd use d_ob1 else p = &d_ob2; // if even use d_ob2 p->func(); // call appropriate function } return 0; } Việc chọn lựa để thực thi phiên bản hàm ảo nào (hàm func() của lớp derived1 hay hàm func() của lớp derived2) chỉ được quyết đònh trong lúc run-time. Điều này không thể nào thực hiện được ở thời điểm biên dòch chương trình. 5/ Sử dụng hàm ảo để triển khai cách thức giao diện Ví dụ 2.4 // Use virtual function to define interface. #include <iostream.h> class area { double dim1, dim2; // dimensions of figure public: void setarea(double d1, double d2) { dim1 = d1; dim2 = d2; } [...]... // point to queue p = &q_ob; p->store(1); 2 89 Chương 9 Tính đa hình p->store(2); p->store(3); cout store(2); p->store(3); cout func(); // use derived2's func() return 0; Điều gì xảy ra khi cả hai lớp dẫn xuất đều không tái đònh hàm ảo func() ? Chương 9 Tính đa hình 285 Bài tập III 1 Hãy tạo ra một đối tượng cho lớp area trong ví dụ 3.1 chương 9, điều gì sẽ xảy ra ? 2 Trong ví dụ 3.2 chương 9, thử xoá phần tái đònh hàm ảo func() của... virtual func-name(arg-list) = 0 ; Hàm được gán trò zero với mục đích thông báo cho trình biên dòch biết là không có gì trong hàm là liên quan đến lớp cơ sở Khi hàm ảo là một hàm ảo thuần túy, nó buộc các lớp dẫn xuất phải tái đònh nó, nếu không trình biên dòch sẽ báo lỗi lúc biên dòch chương trình • Nếu một lớp có chứa hàm ảo thuần túy, lớp đó được gọi là lớp trừu tượng Lớp trừu tượng được tạo ra... area *p; rectangle r; 2 79 Chương 9 Tính đa hình 280 triangle t; r.setarea(3.3, 4.5); t.setarea(4.0, 5.0); p = &r; cout next = head; head = item; if(!tail) tail = head; } int stack::retrieve() { int i; list *p; if(!head) { cout num; p = head; head = head->next; delete p; return i; . dòch chương trình (compiler) thông qua việc quá tải các hàm và toán tử . Cách 2, đa hình được hổ trợ ở thời điểm thực thi chương trình (run-time) thông qua các hàm ảo . Cách này giúp lập trình. thực thi chương trình (run-time) . Khi gọi các hàm liên kết muộn, điạ chỉ của hàm được gọi chỉ biết được khi run-time . Trong C++, hàm ảo là một đối tượng liên kết muộn. Chỉ khi run-time,. sở, chương trình mới xác đònh kiểu của đối tượng bò trỏ và biết được phiên bản nào của hàm ảo được thực thi. Ưu điểm : tính linh hoạt của nó ở thời gian run-time, điều này giúp cho chương trình

Ngày đăng: 22/07/2014, 18:22

TỪ KHÓA LIÊN QUAN

w