Tải bản đầy đủ (.pptx) (16 trang)

Đa hình (lập TRÌNH HƯỚNG đối TƯỢNG SLIDE)

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (303.61 KB, 16 trang )

Bài 7: Đa hình


Giới thiệu
• Đa hình là khả năng cho phép:


Cho phép các lớp được định nghĩa các phương thức trùng
nhau: cùng tên, cùng số lượng và kiểu tham số, cùng kiểu
trả về. Việc định nghĩa phương thức trùng nhau của các lớp
kế thừa nhau còn được gọi là sự nạp chồng phương thức.



Khi gọi các phương thức trùng tên, dựa vào đối tượng đang
gọi mà chương trình sẽ thực hiện phương thức của lớp tương
ứng, và do đó, sẽ cho các kết quả khác nhau.



Ví dụ: Xây dựng lớp người, lớp sinh viên, lớp giáo viên cùng
có phương thức Nhap() và phương thức Xuat().

 Như vậy đa hình là khả năng cho phép viết chương trình để
xử lý tổng quát các đối tượng của tất cả các lớp trong một phân
cấp như các đối tượng của lớp cơ sở. Do vậy một thông điệp
được gửi đi mà không cần biết đối tượng nhận thuộc lớp nào.


Các phương thức ảo
• Xét ví dụ: B, C kế thừa từ A.


3 lớp A,B,C đều có phương thức xuat()
A *p, *q, *r; // p, q, r là con trỏ kiểu A
A a; // a là đối tượng kiểu A
B b; // b là đối tượng kiểu B
C c; // c là đối tượng kiểu c
//----------------p = &a ;
q = &b ;
r = &c ;
//-----------p->xuat();
q->xuat();
r->xuat();
Cả ba câu lệnh đều gọi đến A::xuat()

Giải pháp: Xây dựng xuat() là phương thức ảo


Các phương thức ảo





Giả sử A là lớp cơ sở.
B,C,D là lớp dẫn xuất.
Giả sử các lớp này đều có phương thức xuat().
Để định nghĩa các phương thức này là ảo có 2 cách:
o Hoặc thêm từ khố virtual vào dòng tiêu đề của
phương thức bên trong định nghĩa lớp cơ sở A.
o Hoặc thêm từ khố virtual vào dịng tiêu đề bên
trong định nghĩa của tất cả các lớp A, B, C và D



Các phương thức ảo
• Khi xây dựng một cấu trúc cây phân cấp, người lập trình
chuẩn bị các hành vi chung của lớp đó.
• Hành vi giao tiếp chung sẽ được dùng để thể hiện cùng
hành vi, nhưng có các hành động khác nhau  đó là
phương thức ảo.
Ví dụ: Đọc thêm ví dụ trang 122 - giáo trình LTHĐT


Các phương thức ảo
class Base
{
public:
virtual void Display()
{
cout< <"class Base"<
}
};
void Show(Base *B)
{
B->Display(); //Con trỏ B
chỉ đến phương thức Display()
//(của lớp Base hoặc lớp
Derived) //tùy vào lúc chạy
chương trình.
}


class Derived : public Base
{
public:
virtual void Display()
{
cout<<"class Derived"<}
};
int main()
{
Base *B=new Base;
Derived *D=new Derived;
B->Display(); //Base::Display()
D->Display(); //Derived::Display()
Show(B); //Base::Display()
Show(D); //Derived::Display()
return 0;
}


Các phương thức ảo
• Kết quả khi chạy chương trình:

• Giải thích:
• Nếu khơng có khai báo virtual cho phương thức Base::Display() khi đó
lệnh Show(D) trong hàm main() sẽ gọi đến Base::Display() (vì đối tượng
của lớp dẫn xuất cũng là đối tượng của lớp cơ sở).
• 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à tùy thuộc vào kiểu của tham số vào lúc chạy chương

trình. ( khi truyền tham số B thì Base::Display() được gọi, khi truyền D
thì Derived::Display() được gọi).


Các phương thức ảo
• Giải thích cơ chế:


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à 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 vptr.

• 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


Các phương thức ảo
• Giải thích cơ chế:


Xét ví dụ trên: 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 hồn tồn giống một đối

tượng của Base chính cống như B.



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(), trong khi 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.
 Do vậy lệnh: Show(D);gọi đến phương thức Derived::Display()


Các phương thức ảo
• Đặc trưng của phương thức ảo.
• Phương thức ảo khơng thể là các phương thức tĩnh.
• Khơng cần thiết phải ghi rõ từ khóa virtual trước định
nghĩa một phương thức ảo trong lớp dẫn xuất.
• Khi một phương thức được định nghĩa là ảo, từ lớp cơ sở
đến 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 ta sơ xuất định
nghĩa phương thức khác đi thì trình biên dịch sẽ hiểu đó là
phương thức khác.


Lớp cơ sở trừu tượng
• Trong q trình thiết kế hướng đối tượng, để tạo hệ thống phả hệ
mang tính kế thừa cao người lập trình phải đốn trước sự phát triển
của cấu trúc từ đó lựa chọn những thành viên phù hợp cho lớp trên
cùng.
• Để tránh tình trạng xây dựng các đối tượng lãng phí bộ nhớ, C++
cho phép thiết kế các lớp có các phương thức ảo khơng làm gì cả, và

cũng khơng thể tạo ra đối tượng của lớp đó.
 Những lớp như vậy gọi là lớp trừu tượng.


Lớp cơ sở trừu tượng
• Là lớp chỉ dùng làm cơ sở cho các lớp khác.
• Khơng được khởi tạo một đối tượng thuộc lớp trừu tượng.
• Các phương thức của lớp trừu tượng là các phương thức
ảo thuần túy.
virtual void tên_phương_thức() = 0 ;
• Bất kỳ lớp nào dẫn xuất từ một lớp cớ sở trừu tượng phải
định nghĩa lại tất cả các phương thức thuần ảo mà nó thừa
hưởng.


Lớp cơ sở trừu tượng

• Trong cây phân cấp trên khơng phải lớp nào cũng cần hàm print(), nhưng
nó được tạo ra ở khắp nơi để tạo bộ mặt chung cho mọi lớp của cây phân
cấp.
• A::Print() thường là phương thức ảo để có được tính đa hình.


Lớp cơ sở trừu tượng
• Khi đó với hàm
void Show(A* a)
{
a->Print();
}
ta có thể truyền đối tượng đủ kiểu cho nó (A, B, C, D hoặc E) mà vẫn gọi đến đúng

phuơng thức Print() phù hợp, dù kiểu của đối tượng lúc biên dịch vẫn cịn chưa
biết.
• Để tránh trình trạng vơ tình tạo ra đối tượng thuộc lớp A, ta thường
xây dựng lớp trừu tượng với các phương thức thuần ảo (pure virtual
function) như sau:
class A
{
public:
virtual void Print() = 0;
};

Xem ví dụ trang 126- giáo trình LTHDT


Lớp cơ sở trừu tượng
Chú ý:
• Chúng ta khơng thể tạo ra một đối tượng của lớp trừu tượng, nhưng
hoàn tồn có thể tạo ra một con trỏ trỏ đến lớp này (vì con trỏ khơng
phải là đối tượng thuộc lớp) hoặc là một tham chiếu.
• Nếu trong lớp kế thừa từ lớp trừu tượng chúng ta không định nghĩa
phương thức thuần ảo, do tính kế thừa nó sẽ bao hàm phương thức
thuần ảo của lớp cơ sở, nên lớp dẫn xuất này sẽ trở thành lớp trừu
tượng.
• Theo định nghĩa lớp trừu tượng, nếu trong lớp dẫn xuất (từ lớp cơ
sở trừu tượng) chúng ta định nghĩa thêm một phương thức thuần ảo
khác, lớp này cũng sẽ trở thành lớp trừu tượng.


Các thành viên ảo của một lớp
• Các tốn tử ảo:

• Các tốn tử bản chất cũng là các phương thức nên ta có thể định nghĩa
các tốn tử là ảo, chú ý kiểu của toán hạng phải sử dụng kiểu của lớp cơ
sở gốc có tốn tử ảo.
• Ví dụ
class A
{ …
virtual A& operator + (A& T);
virtual A& operator = (A& T);

… }
Class B: public A
{…
virtual A& operator + (A& T);
virtual A& operator = (A& T);

… }



×