Đa hình trong C ++
Từ polymorphismnghĩa là có nhiều hình thức. Thông thường, tính đa hình xảy ra khi có một hệ thống phân cấp của các lớp và chúng có liên quan với nhau bằng cách kế thừa.
Tính đa hình trong C ++ có nghĩa là một lệnh gọi đến một hàm thành viên sẽ khiến một hàm khác được thực thi tùy thuộc vào loại đối tượng gọi hàm.
Hãy xem xét ví dụ sau trong đó một lớp cơ sở đã được dẫn xuất bởi hai lớp khác:
#include <iostream>
using namespace std;
class Shape {
protected:
int width, height;
public:
Shape( int a = 0, int b = 0){
width = a;
height = b;
}
int area() {
cout << "Parent class area :" <<endl;
return 0;
}
};
class Rectangle: public Shape {
public:
Rectangle( int a = 0, int b = 0):Shape(a, b) { }
int area () {
cout << "Rectangle class area :" <<endl;
return (width * height);
}
};
class Triangle: public Shape {
public:
Triangle( int a = 0, int b = 0):Shape(a, b) { }
int area () {
cout << "Triangle class area :" <<endl;
return (width * height / 2);
}
};
// Main function for the program
int main() {
Shape *shape;
Rectangle rec(10,7);
Triangle tri(10,5);
// store the address of Rectangle
shape = &rec;
// call rectangle area.
shape->area();
// store the address of Triangle
shape = &tri;
// call triangle area.
shape->area();
return 0;
}
Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:
Parent class area :
Parent class area :
Lý do cho kết quả đầu ra không chính xác là lời gọi của vùng hàm () đang được trình biên dịch đặt một lần làm phiên bản được định nghĩa trong lớp cơ sở. Đây được gọi làstatic resolution của lệnh gọi hàm, hoặc static linkage- lệnh gọi hàm được cố định trước khi chương trình được thực thi. Điều này đôi khi cũng được gọi làearly binding vì hàm area () được thiết lập trong quá trình biên dịch chương trình.
Nhưng bây giờ, chúng ta hãy thực hiện một sửa đổi nhỏ trong chương trình của chúng ta và bắt đầu khai báo vùng () trong lớp Shape với từ khóa virtual để nó trông như thế này -
class Shape {
protected:
int width, height;
public:
Shape( int a = 0, int b = 0) {
width = a;
height = b;
}
virtual int area() {
cout << "Parent class area :" <<endl;
return 0;
}
};
Sau sửa đổi nhỏ này, khi mã ví dụ trước được biên dịch và thực thi, nó tạo ra kết quả sau:
Rectangle class area
Triangle class area
Lần này, trình biên dịch xem xét nội dung của con trỏ thay vì kiểu của nó. Do đó, vì địa chỉ của các đối tượng thuộc lớp tri và rec được lưu trữ trong * shape nên hàm area () tương ứng được gọi.
Như bạn có thể thấy, mỗi lớp con có một triển khai riêng cho vùng hàm (). Đây là cáchpolymorphismthường được sử dụng. Bạn có các lớp khác nhau với một hàm có cùng tên, và thậm chí là các tham số giống nhau, nhưng với các cách triển khai khác nhau.
Chức năng ảo
A virtual function là một hàm trong lớp cơ sở được khai báo bằng từ khóa virtual. Định nghĩa trong lớp cơ sở một hàm ảo, với một phiên bản khác trong lớp dẫn xuất, báo hiệu cho trình biên dịch rằng chúng ta không muốn liên kết tĩnh cho hàm này.
Những gì chúng ta muốn là lựa chọn hàm được gọi tại bất kỳ điểm nhất định nào trong chương trình để dựa trên loại đối tượng mà nó được gọi. Loại hoạt động này được gọi làdynamic linkage, hoặc là late binding.
Chức năng ảo thuần túy
Có thể bạn muốn đưa một hàm ảo vào một lớp cơ sở để nó có thể được định nghĩa lại trong một lớp dẫn xuất cho phù hợp với các đối tượng của lớp đó, nhưng không có định nghĩa có ý nghĩa nào mà bạn có thể đưa ra cho hàm trong lớp cơ sở .
Chúng ta có thể thay đổi vùng hàm ảo () trong lớp cơ sở thành như sau:
class Shape {
protected:
int width, height;
public:
Shape(int a = 0, int b = 0) {
width = a;
height = b;
}
// pure virtual function
virtual int area() = 0;
};
= 0 cho trình biên dịch biết rằng hàm không có nội dung và hàm ảo ở trên sẽ được gọi pure virtual function.