Giới thiệu
Đa hình là một trong những khía cạnh quan trọng của lập trình hướng đối tượng (OOP) trong C++, hoạt động dựa trên cơ chế kế thừa. Vì vậy, để học tập có hệ thống về đa hình, bạn cần nắm vững kiến thức về kế thừa.
Khái niệm
Tác dụng của đa hình có thể được ví như chính sách mua vé khác nhau dành cho các đối tượng khác nhau: quân nhân được ưu tiên, trẻ em giảm giá, người lớn mua vé đầy đủ. Trong ví dụ trên, chúng ta thấy rõ tác dụng của đa hình: cùng một hệ thống (lớp), nhưng với các đối tượng có tình huống và vai trò khác nhau, hệ thống tạo ra các kết quả tương ứng.
Định nghĩa và thực hiện đa hình
Để tạo nên đa hình, cần đáp ứng hai điều kiện sau:
- Sử dụng tham chiếu hoặc con trỏ của lớp cha để gọi hàm cơ sở
- Hàm thực hiện đa hình trong lớp cha phải là hàm ảo, và lớp con phải ghi đè/hàm thực hiện lại hàm đó
2.1 Hàm ảo
Hàm được đánh dấu bằng từ khóa virtual được gọi là hàm ảo
class DongVat
{
virtual void TiengKeu()
{}
};
2.2 Ghi đè hàm ảo
- Khi lớp con thực hiện lại hàm ảo của lớp cha, đó được gọi là ghi đè hàm ảo.
- Kiểu trả về, danh sách tham số, và tên hàm của lớp con phải khớp với lớp cha.
class NguoiLon
{
virtual void MuaVe()
{
cout << "Người lớn - Giá đầy đủ" << endl;
}
}
class TreEm : public NguoiLon
{
virtual void MuaVe() // Kiểu trả về, danh sách tham số, tên hàm phải khớp với lớp cha
{
cout << "Trẻ em - Giá giảm 50%" << endl; // Ghi đè hàm ảo của lớp cha
}
}
2.3 Hai trường hợp đặc biệt khi ghi đè hàm ảo
2.3.1 Biến đổi kiểu trả về (lớp cơ sở và lớp dẫn xuất có kiểu trả về khác nhau):
C++ cho phép lớp cha trả về con trỏ/tham chiếu kiểu lớp cha, và lớp con trả về con trỏ/tham chiếu kiểu lớp con (chỉ cần biết)
class LopA
{
public:
virtual LopA* Ham() { return new LopA; }
};
class LopB : public LopA
{
public:
virtual LopB* Ham() { return new LopB; }
};
2.3.2. Ghi đè hàm hủy
Nếu hàm hủy của lớp cha là hàm ảo, thì hàm hủy của lớp con sẽ tạo nên ghi đè, vì tên hàm hủy sẽ được biên dịch thành destructor. Lúc này, hàm hủy của lớp cha và lớp con có cùng tên, đáp ứng điều kiện của đa hình, nên tạo nên ghi đè hàm ảo.
Thứ tự gọi hàm hủy: lớp con → lớp cha Thứ tự gọi hàm tạo: lớp cha → lớp con
2.4 Từ khóa override và final trong C++11
Như ta thấy, yêu cầu để tạo nên đa hình rất nghiêm ngặt, ngay cả một lỗi nhỏ trong ký tự cũng có thể khiến đa hình không hoạt động. Một số người nói rằng trình biên dịch sẽ báo lỗi, rất dễ sửa. Nhưng chúng ta cần biết, cú pháp đa hình chỉ được kiểm tra lúc biên dịch, và lỗi không xuất hiện ngay lập tức. Nếu trong các dự án lớn cần thời gian biên dịch lâu, lỗi này sẽ gây lãng phí nhiều thời gian. Vì vậy, C++11 đã giới thiệu hai từ khóa này:
-
final: dùng để đánh dấu hàm ảo, cho biết hàm này không thể bị ghi đè thêm nữa
-
override: kiểm tra xem hàm ảo của lớp con có thực sự ghi đè đúng hàm ảo của lớp cơ sở hay không, nếu không (ghi đè không đúng) thì trình biên dịch sẽ báo lỗi
-
overrideđược đặt ở hàm của lớp con -
Ở đây, hàm của lớp con có thêm một tham số kiểu int, trình biên dịch sẽ báo lỗi ngay