Kế thừa & đa hình trong lập trình hướng đối tượng | CppDeveloper

Tính kế thừa – Inheritance

Một trong những đặc tính quan trọng nhất của OOP là thừa kế. Ưu điểm của đặc tính thừa kế : sử dụng lại những đoạn code đã có trong chương trình 1 cách hiệu suất cao. Khi tạo 1 class, thay vì việc viết 1 class mới trọn vẹn, người lập trình viên hoàn toàn có thể thừa kế một số ít thuộc tính và phương pháp từ 1 class đã có trong project. Class đã có trước đấy gọi là lớp cơ sở ( Base Class ), class kế thừa từ Base Class ( hay superclass ) gọi là lớp dẫn xuất ( Derived Class ) .
Do tính thừa kế khá rõ ràng và dễ hiểu nên mình sẽ không lý giải nhiều về thừa kế nữa. Bạn nào muốn tìm hiểu và khám phá thêm thì tìm hiểu thêm link này nhé : https://www.cppdeveloper.com/c-co-ban/6-1-1-dinh-nghia-mot-phan-lop-don-gian-1/

Tính đa hình – Polymorphism

Tính Đa hình – Polymorphism là một đặc thù đặc trưng rất thần thánh của OOP. Trong bài này mình sẽ hầu hết tập trung chuyên sâu lý giải về Polymorphism cho những bạn .

Đầu tiên mình sẽ đưa ví dụ về Polymorphism ở ngoài đời thực để anh em dễ hình dung đã. Ví dụ, cùng là một người nhưng tuỳ từng ngữ cảnh sẽ đóng vai trò khác nhau, một người đàn ông vừa là nhân viên (khi đi làm), vừa là một người chồng (đối với vợ) và là người cha (đối với con),… nói chung là anh ta sẽ biến hình thành con người khác nhau tuỳ từng ngữ cảnh.

Trong OOP và cụ thể là trọng ngôn ngữ C++ thì Polymorphism có 2 dạng:

  • Dạng 1 – Compile time Polymorphism: Một class có nhiều hàm cùng tên nhưng khác nhau về số lượng tham số hoặc kiểu dữ liệu của tham số. Khi call hàm cùng tên đó thì trong quá trình biên dịch, compiler sẽ quyết định hàm nào (trong số các hàm cùng tên) sẽ được call dựa trên số lượng tham số và kiểu dữ liệu của tham số truyển vào hàm. Việc định nghĩa các hàm cùng tên được gọi là overloading – nạp chồng hàm.
  • Dạng 2 – Runtime Polymorphism: Cùng một class có thể cho ra nhiều biến thể, không phải được định nghĩa bởi lớp đó, mà bởi các lớp con của nó. Đây là một phương pháp để định nghĩa lại hành vi của lớp cơ sở mà không phải sửa code của lớp cơ sở. Nếu call hàm của đối tượng của lớp dẫn xuất thông qua con trỏ của lớp cơ sở thì việc hàm nào được call sẽ được quyết định lúc Runtime. Runtime Polymorphism được thực hiện bằng phương pháp overriding – ghi đè phương thức.

Sau đây mình sẽ đưa code sample cho 2 dạng Polymorphism ở trên.

Sample 1 – Compile time Polymorphism

123456789101112131415161718192021222324252627

#include

usingnamespacestd;

classPrintData{

public:

voidprint(inti){

cout<<" Printing int : "<

}

voidprint(doublef){

cout<<" Printing float : "<

}

voidprint(char*c){

cout<<" Printing character : "<

}

};

intmain(void){

PrintDatapd;

pd.print(5);/ / Call print to print integer

pd.print(500.263);/ / Call print to print float

pd.print(” Hello C + + “);/ / Call print to print character

return0;

}

Trong OOP và đơn cử là trọng ngôn từ C + + thì Polymorphism có 2 dạng : Sau đây mình sẽ đưa code sample cho 2 dạng Polymorphism ở trên. —

Ta có class PrintData có 3 phương thức cùng tên là print(), 3 phương thức này cùng có một tham số nhưng kiểu của tham số thì khác nhau, lần lượt là int, double và char*. Trong hàm main gọi đến phương thức print() 3 lần với 3 tham số khác nhau, khi đó trình biên dịch sẽ dựa vào kiểu ‘(hoặc giá trị) của tham số truyền vào và tự quyết định phương thức nào trong 3 phương thức cùng tên sẽ được gọi. Chương trình này chạy sẽ ra kết quả trên console như sau:

123

Printingint:5

Printingfloat:500.263

Printingcharacter:HelloC++

Sample 2 – Runtime Polymorphism

1234567891011121314151617181920212223242526272829303132333435

#include

usingnamespacestd;

classPet

{

protected:

stringName;

public:

Pet(stringn){Name=n;}

virtualstringgetSound(){return” “;};

voidmakeSound(void){cout<

};

classCat:publicPet{

public:

Cat(stringn):Pet(n){}

stringgetSound(){return” Meow ! Meow ! “;};

};

classDog:publicPet{

public:

Dog(stringn):Pet(n){}

stringgetSound(){return” Woof ! Woof ! “;};

};

intmain(void){

Pet*a_pet=newCat(” Kitty “);;

a_pet->makeSound();

deletea_pet;

a_pet=newDog(” Doggie “);

a_pet->makeSound();

deletea_pet;

return0;

}

12

Kittysays:Meow!Meow!

Doggiesays:Woof!Woof

!

Chương trình này sẽ xuất ra màn hình hiển thị nội dung như sau →

Ở đây ta có class cha là Pet định nghĩa phương thức makeSound(), phương thức này đưa ra mô tả về tiếng kêu của con vật. Tiếng kêu được định nghĩa bởi hàm getSound(), hàm này được khai báo là hàm ảo (virtual) ở class cha, điều đó cho phép các class con như Cat, Dog định nghĩa lại (overriding) hàm này cho phù hợp với đặc điểm riêng của chúng. Chính vì vậy ở hàm main dù cùng là con trỏ a_pet nhưng khi gọi hàm makeSound() 2 lần lại ra 2 nội dung khác nhau tuỳ thuộc vào đối tượng đang được trỏ tới lúc đó là đối tượng của class con nào (Dog hay Cat)

Xem thêm

— Phạm Minh Tuấn ( Shun ) —