Tính đa hình trong cơ sở dữ liệu

27 753 2
Tính đa hình trong cơ sở dữ liệu

Đ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

Tính đa hình trong cơ sở dữ liệu

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. • 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 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 sở, thì thể sử dụng p để trỏ tới bất kỳ lớp nào được suy ra từ lớp sở. Chẳng hạn, hai lớp 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 sở thể trỏ tới bất kỳ lớp dẫn xuất nào của lớp sở mà không gây ra báo lỗi khác kiểu. Song chỉ 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 sở. Bởi vì con trỏ của lớp sở chỉ biết lớp 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 sở. (Việc sử dụng linh hoạt kiểu 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 sở. Ví dụ 1.1 Dùng con trỏ của lớp 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 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 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 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 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 hai hay nhiều lớp dẫn xuất của một lớp sở nào đó, và chúng đều chứa hàm ảo, thì con trỏ của lớp sở 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à thể gọi đến nhiều phiên bản khác nhau của các hàm ảo. • Một lớp 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 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 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 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; } [...]... } Ví dụ 4.2 Dùng đa hình để xử lý các biến cố ngẫu nhiên. Sử dụng các khai báo và định nghiã lớp ở ví dụ 4.1 . int main() { list *p ; stack s_ob; queue q_ob; 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 294 DT_SINGLELINE... lớp này là sorted thừa kế lớp sở list. Lớp sorted chứa hai hàm chung là - void store(int i) chức năng thêm phần tử mới vào danh sách sao cho chúng thứ tự tăng dần. - và int retrieved() chức năng hiển thị các phần tử trong danh sách. 2. Hãy viết một chương trình áp dụng tính đa hình. Bài tập chương 9 Chương 9 Tính đa hình 283 class triangle ... 9 Tính đa hình 280 triangle t; r.setarea(3.3, 4.5); t.setarea(4.0, 5.0); p = &r ; cout << "Rectangle has area: " << p->getarea() << '\n'; p = &t ; cout << "Triangle has area: " << p->getarea() << '\n'; return 0; } @ Việc khai báo hàm ảo trong lớp sở area chỉ mang tính. .. định các hàm ảo của hai lớp dẫn xuất trên để chúng xuất ra số nguyên dưới dạng số hec và số oct. 2. Viết chương trình tạo ra một lớp sở distance lưu khoảng cách giữa hai điểm với kiểu dữ liệu double. class distance { public : double d; Chương 9 Tính đa hình 289 cout << "Allocation error.\n"; exit(1); } item->num = i; // put on front of list for stack-like... &q_ob ; // point to queue p->store(1); 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 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... function) Một trường hợp khá phổ biến khi lớp sở tự nó không phải là một lớp hoàn chỉnh , lúc đó hàm ảo được khai báo giữ chỗ chứ không thực hiện công việc cụ thể. Lớp sở này chỉ cung cấp một bộ khung gồm các hàm và biến và để dành cho các lớp dẫn xuất các phần định nghóa còn lại. Các lớp dẫn xuất phải tái định tất cả các hàm ảo khai báo trong lớp sở đó. Để đảm bảo cho điều này, C++ hổ trợ... Tính đa hình 275 Việc tái định hàm ảo trong một lớp dẫn xuất 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 thể Vị trí Việc tái định hàm ảo trong. .. void func() Chương 9 Tính đa hình 282 Tuy nhiên, thể tạo ra một con trỏ đến lớp trừu tượng bởi vì điều này cần thiết để hổ trợ cho đa hình trong khi run-time . Điều này cũng cho phép tham chiếu đến một lớp trừu tượng. • Khi một hàm ảo được kế thừa, bản chất ảo của nó cũng được kế thừa . Điều này nghiã là khi một lớp dẫn xuất kế thừa hàm ảo từ lớp sở, một lớp dẫn xuất thứ hai... hàm ảo thuần túy. • Hàm ảo thuần túy không một định nghiã nào liên quan đến lớp sở. Nó chỉ có dạng hàm mà thôi, cách khai báo virtual <type> 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 trong hàm là liên quan đến lớp 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... các hàm trên được xác định rõ ràng trong lúc biên dịch. Ưu điểm : gọi các hàm liên kết sớm là kiểu gọi hàm nhanh nhất. Nhược điểm : thiếu tính linh hoạt. • Liên kết muộn (late binding) gắn liền với những biến cố xuất hiện trong lúc 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 . tượng ? IV/ p dụng đa hình Tại sao cần sử dụng đa hình ? 1/ Đa hình rất quan trọng vì nó đơn giản hoá các hệ thống phức tạp. • Đa hình là một quá trình. 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

Ngày đăng: 04/09/2012, 15:12

Từ khóa liên quan

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan