Polymorphism phép tái sử dụng mã bằng cách cho phép các đối tượng của loại liên quan đến được đối xử như nhau.
Hãy xem xét rằng bạn có thể cần hàng chục lớp con mà hành xử khác nhau:
struct Shape1: public Shape { /* .. */ }; // triangle
struct Shape2: public Shape { /* .. */ }; // rectangle
// ...
struct ShapeN: public Shape { /* .. */ }; // projection of rhombic triacontahedron
Hãy xem xét rằng bạn có thể cần để xử lý đối tượng được trỏ bởi một loạt các Shape
con trỏ.
Với đa hình, bạn cần có một véc tơ duy nhất, và một vòng duy nhất với chức năng ảo gọi:
std::vector<Shape*> v = get_shape_vector();
for(Shape* s : v)
s->draw();
Nếu không có đa hình, bạn sẽ phải quản lý một mảng riêng cho từng loại và xử lý chúng một cách riêng biệt:
std::vector<Shape1> v1 = get_shape1_vector();
std::vector<Shape2> v2 = get_shape2_vector();
// ...
std::vector<ShapeN> vN = get_shapeN_vector();
for(Shape1& s : v1)
s.draw();
for(Shape2& s : v2)
s.draw();
// ...
for(ShapeN& s : vN)
s.draw();
3 dòng mã sử dụng đa hình là cách dễ dàng hơn để duy trì hơn 3 * N dòng mã không sử dụng đa hình.
Hãy xem xét rằng bạn có thể cần phải sửa đổi quy trình. Có lẽ bạn muốn thêm một cuộc gọi hàm trước khi vẽ. Đây là đơn giản khi bạn có tính đa hình về phía bạn:
void pre_draw(Shape*);
for(Shape* s : v) {
pre_draw(s);
s->draw();
}
Nếu không có đa hình, bạn cần phải xác định hàng chục chức năng và chỉnh sửa từng chục bẹ:
void pre_draw1(Shape1&);
void pre_draw2(Shape2&);
// ...
void pre_drawN(ShapeN&);
for(Shape1& s : v1) {
pre_draw1(s);
s.draw();
}
for(Shape2& s : v1) {
pre_draw2(s);
s.draw();
}
// ...
for(ShapeN& s : v1) {
pre_drawN(s);
s.draw();
}
Hãy xem xét rằng bạn có thể thêm hình dạng sau . Với tính đa hình, bạn chỉ cần xác định loại mới và hàm ảo. Bạn có thể chỉ cần thêm con trỏ vào nó vào mảng và chúng sẽ được xử lý giống như các đối tượng của mọi loại tương thích khác.
struct ShapeN1: public Shape { /* .. */ }; // yet another shape
Nếu không có polymorhpism, ngoài việc xác định loại mới, bạn sẽ phải tạo một mảng mới cho nó. Và bạn sẽ cần phải tạo một hàm pre_draw
mới. Và bạn sẽ cần phải thêm một vòng lặp mới để xử lý chúng.
void pre_drawN1(ShapeN1&);
// ...
std::vector<ShapeN1> vN1 = get_shapeN1_vector();
// ...
for(ShapeN1& s : vN1) {
pre_drawN1(s);
s.draw();
}
Thực tế, bạn sẽ cần phải đi qua toàn bộ cơ sở mã cho những vị trí mà mỗi loại hình được xử lý và thêm mã cho loại mới đó.
Bây giờ, N có thể nhỏ hoặc tuyệt vời. N càng lớn thì tính đa hình lặp lại càng tránh được. Tuy nhiên, không có vấn đề làm thế nào vài lớp con bạn có, không phải xem xét thông qua toàn bộ cơ sở mã của bạn khi bạn thêm một cái mới là một lợi ích tuyệt vời.
Không cần phải có con trỏ mới trong trường hợp của bạn. Nhưng điều đó không liên quan đến "đa hình cần (cho) đa hình ..." – juanchopanza
Điểm của các hàm ảo là để chúng ta có thể định nghĩa hành vi khi chạy và cho phép sử dụng động các đối tượng. Đa hình là tên được đặt cho điều này. – Lawrence
Ví dụ: bạn có thể muốn tạo bộ sưu tập hình dạng. Xem xét '' 'std :: vector' ''. Nó có thể chứa các hình dạng khác nhau nhưng bạn có thể làm những việc chung cho tất cả chúng. –
isapego