<< Chapter < Page Chapter >> Page >

gọi đến Base::Display() vì đối tượng lớp dẫn xuất cũng là đối tượng lớp cơ sở (nghĩa là tdb tự động chuyển đổi kiểu: đối tượng D kiểu Derived chuyển thành kiểu Base.

Nhờ khai báo virtual cho phương thức Base::Display() nên sẽ không thực hiện gọi phương thức Base::Display() một cách cứng nhắc trong hàm Show() mà chuẩn bị một cơ chế mềm dẻo cho việc gọi phương thức Display() tùy thuộc vào sự xác định kiểu của tham số vào lúc chạy chương trình.

Cơ chế đó ra sao? Khi nhận thấy có khai báo virtual trong lớp cơ sở, trình biên dịch sẽ thêm vào mỗi đối tượng của lớp cơ sở và các lớp dẫn xuất của nó một con trỏ chỉ đến bảng phương thức ảo (virtual function table). Con trỏ đó có tên là vptr (virtual pointer). Bảng phương thức ảo là nơi chứa các con trỏ chỉ đến đoạn chương trình đã biên dịch ứng với các phương thức ảo. Mỗi lớp có một bảng phương thức ảo. Trình biên dịch chỉ lập bảng phương thức ảo khi bắt đầu có việc tạo đối tượng của lớp. Đến khi chương trình chạy, phương thức ảo của đối tượng mới được nối kết và thi hành thông qua con trỏ vptr.

Trong ví dụ 6.1, lệnh gọi hàm: Show(D);

Đối tượng D thuộc lớp Derived tuy bị chuyển đổi kiểu thành một đối tượng thuộc lớp Base nhưng nó không hoàn toàn giống một đối tượng của Base chính cống như B. Nếu như con trỏ vptr trong B chỉ đến vị trí trên bảng phương thức ảo ứng với phương thức Base::Display(), thì con trỏ vptr trong D vẫn còn chỉ đến phương thức Derived::Display() cho dù D bị chuyển kiểu thành Base. Đó là lý do tại sao lệnh: Show(D);

gọi đến phương thức Derived::Display().

    Các đặc trưng của phương thức ảo:

Phương thức ảo không thể là các hàm thành viên tĩnh.

Một phương thức ảo có thể được khai báo là friend trong một lớp khác nhưng các hàm friend của lớp thì không thể là phương thức ảo.

Không cần thiết phải ghi rõ từ khóa virtual khi định nghĩa một phương thức ảo trong lớp dẫn xuất (để cũng chẳng ảnh hưởng gì).

Để sự kết nối động được thực hiện thích hợp cho từng lớp dọc theo cây phả hệ, một khi phương thức nào đó đã được xác định là ảo, từ lớp cơ sở đến các lớp dẫn xuất đều phải định nghĩa thống nhất về tên, kiểu trả về và danh sách các tham số. Nếu đối với phương thức ảo ở lớp dẫn xuất, chúng ta lại sơ suất định nghĩa các tham số khác đi một chút thì trình biên dịch sẽ xem đó là phương thức khác. Đây chính là điều kiện để kết nối động.

Ví dụ 6.2:

2: #include<iostream.h>

3:

4: class Base

5: {

6: public:

7: virtual void Print(int A,int B);

8: };

9:

10: class Derived : public Base

11: {

12: public:

13: virtual void Print(int A,double D);

14: };

15:

16: void Base::Print(int A,int B)

17: {

18: cout<<"A="<<A<<",B="<<B<<endl;

19: }

20:

21: void Derived::Print(int A,double D)

22: {

23: cout<<"A="<<A<<",D="<<D<<endl;

24: }

25:

26: void Show(Base *B)

27: {

28: B->Print(3,5);

29: }

30:

31: int main()

32: {

33: Base *B=new Base;

34: Derived *D=new Derived;

35: Show(B); //Base::Print()

36: Show(D); //Base::Print()

37: return 0;

38: }

Chúng ta chạy ví dụ 6.2 , kết quả ở hình 6.2

Hình 6.2: Kết quả của ví dụ 6.2

Trong ví dụ 6.2, trong lớp cơ sở Base và lớp dẫn xuất Derived đều có phương thức ảo Print(). Nhưng quan sát kỹ chúng ta, phương thức Print() trong lớp Derived có tham số thứ hai khác kiểu với phương thức Print() trong lớp Base. Vì thế, chúng ta không thể chờ đợi lệnh ở dòng 36 sẽ gọi đến phương thức Derived::Print(int,double). Phương thức Derived::Print(int,double) nằm ngoài đường dây phương thức ảo nên hàm Show() chỉ luôn gọi đến phương thức Derived::Print(int,int) mà thôi. Do có khai báo virtual đối với phương thức Derived::Print(int,double), chúng ta có thể nói phương thức này sẽ mở đầu cho một đường dây phương thức ảo Print(int,double) mới nếu sau lớp Derived còn có các lớp dẫn xuất của nó.

Get Jobilize Job Search Mobile App in your pocket Now!

Get it on Google Play Download on the App Store Now




Source:  OpenStax, Lập trình hướng đối tượng. OpenStax CNX. Jul 29, 2009 Download for free at http://cnx.org/content/col10794/1.1
Google Play and the Google Play logo are trademarks of Google Inc.

Notification Switch

Would you like to follow the 'Lập trình hướng đối tượng' conversation and receive update notifications?

Ask