Polymorphism trong C++
Xin chào các bạn nhà lập trình đam mê! Hôm nay, chúng ta sẽ bắt đầu hành trình thú vị vào thế giới polymorphism trong C++. Đừng lo lắng nếu từ này có vẻ kháng cự – đến cuối bài học này, bạn sẽ cảm thấy thoải mái với polymorphism như với đôi giày yêu thích của bạn!
Polymorphism là gì?
Trước khi chúng ta nhảy vào mã, hãy hiểu rõ polymorphism có nghĩa là gì. Từ này đến từ tiếng Hy Lạp: 'poly' nghĩa là nhiều và 'morph' nghĩa là hình. Trong lập trình, polymorphism cho phép các đối tượng của các loại khác được xử lý như các đối tượng của kiểu cơ bản chung. Đó như có một remote tiêu chuẩn có thể kiểm soát nhiều thiết bị khác nhau – rất cool, phải không?
Analogy Thực Tế
Tưởng tượng bạn đang ở sở thú. Bạn thấy nhiều loài động vật khác nhau – sư tử, hươu, chim cánh cụt. Chúng tất cả đều là động vật, nhưng hành vi khác nhau. Khi tới giờ ăn, nhu cầu không cần biết chính xác mỗi loài động vật là gì. Họ chỉ cần gọi một lệnh chung "ăn" và mỗi loài động vật sẽ phản hồi theo cách riêng của mình. Đó chính là polymorphism đang hoạt động!
Hàm Ảo
Bây giờ, hãy đi sâu vào chi tiết của polymorphism trong C++, bắt đầu từ các hàm ảo.
Hàm Ảo Là Gì?
Hàm ảo là các hàm đặc biệt trong C++ mà cho phép một chương trình quyết định gọi hàm nào tại thời điểm chạy dựa trên loại đối tượng mà con trỏ hoặc tham chiếu đang liên kết.
Dưới đây là một ví dụ đơn giản:
#include <iostream>
using namespace std;
class Animal {
public:
virtual void makeSound() {
cout << "Con vật này gây ra một tiếng" << endl;
}
};
class Dog : public Animal {
public:
void makeSound() override {
cout << "Chú chó gây ra tiếng: Woof!" << endl;
}
};
class Cat : public Animal {
public:
void makeSound() override {
cout << "Chú mèo gây ra tiếng: Meow!" << endl;
}
};
int main() {
Animal* animal1 = new Dog();
Animal* animal2 = new Cat();
animal1->makeSound(); // Output: Chú chó gây ra tiếng: Woof!
animal2->makeSound(); // Output: Chú mèo gây ra tiếng: Meow!
delete animal1;
delete animal2;
return 0;
}
Hãy phân tích:
- Chúng ta có một lớp cơ bản
Animal
với một hàm ảomakeSound()
. - Chúng ta tạo hai lớp con,
Dog
vàCat
, mỗi lớp đều ghi đè hàmmakeSound()
. - Trong
main()
, chúng ta tạo các con trỏ của kiểuAnimal*
nhưng gán chúng cho các đối tượng củaDog
vàCat
. - Khi chúng ta gọi
makeSound()
, chương trình biết để gọi phiên bản chính xác dựa trên loại đối tượng thực tế, không phải loại con trỏ.
Đó là phép màu của các hàm ảo và polymorphism!
Từ Khóa 'virtual'
Từ khóa virtual
quan trọng ở đây. Nó nói với trình biên dịch rằng hàm này có thể bị ghi đè trong các lớp con. Nếu không có nó, chương trình sẽ luôn gọi phiên bản của hàm trong lớp cơ bản.
Hàm Ảo Đơn
Bây giờ, hãy nâng cấp và nói về các hàm ảo đơn.
Hàm Ảo Đơn Là Gì?
Hàm ảo đơn là một hàm ảo không có thực thi trong lớp cơ bản. Nó được khai báo bằng cách gán 0 cho khai báo hàm.
Dưới đây là một ví dụ:
#include <iostream>
using namespace std;
class Shape {
public:
virtual double area() = 0; // Hàm ảo đơn
};
class Circle : public Shape {
private:
double radius;
public:
Circle(double r) : radius(r) {}
double area() override {
return 3.14159 * radius * radius;
}
};
class Rectangle : public Shape {
private:
double length, width;
public:
Rectangle(double l, double w) : length(l), width(w) {}
double area() override {
return length * width;
}
};
int main() {
Shape* shape1 = new Circle(5);
Shape* shape2 = new Rectangle(4, 5);
cout << "Diện tích hình tròn: " << shape1->area() << endl;
cout << "Diện tích hình chữ nhật: " << shape2->area() << endl;
delete shape1;
delete shape2;
return 0;
}
Trong ví dụ này:
-
Shape
là một lớp cơ bản trừu tượng với một hàm ảo đơnarea()
. -
Circle
vàRectangle
là các lớp cụ thể kế thừa từShape
và cung cấp thực thi riêng củaarea()
. - Chúng ta có thể tạo các con trỏ
Shape
và gán chúng cho các đối tượngCircle
vàRectangle
. - Khi chúng ta gọi
area()
, phiên bản chính xác sẽ được gọi dựa trên loại đối tượng thực tế.
Các Lớp Trừu Tượng
Một lớp có ít nhất một hàm ảo đơn được gọi là lớp trừu tượng. Bạn không thể tạo đối tượng của một lớp trừu tượng, nhưng bạn có thể sử dụng các con trỏ và tham chiếu để các kiểu lớp trừu tượng.
Tại Sao Sử Dụng Polymorphism?
- Độ Linh Hoạt: Nó cho phép bạn viết mã có thể làm việc với các đối tượng của nhiều kiểu.
- Độ Mở Rộng: Bạn có thể thêm các lớp con mới mà không cần thay đổi mã hiện tại.
- Đơn Giản: Nó có thể đơn giản hóa mã bằng cách cho phép bạn xử lý các đối tượng khác nhau một cách đồng đều.
Các Phương Pháp Phổ Biến Trong Polymorphism
Dưới đây là bảng các phương pháp phổ biến được sử dụng trong polymorphism trong C++:
Phương Pháp | Mô Tả |
---|---|
virtual |
Từ khóa được sử dụng để khai báo hàm ảo trong lớp cơ bản |
override |
Từ khóa được sử dụng trong các lớp con để chỉ ra rằng hàm đang ghi đè hàm của lớp cơ bản |
= 0 |
Được sử dụng để khai báo hàm ảo đơn |
dynamic_cast |
Được sử dụng để chuyển đổi an toàn xuống trong các hệ thống lớp polymorphic |
typeid |
Được sử dụng để có thông tin về kiểu tại thời điểm chạy |
Kết Luận
Polymorphism là một tính năng mạnh mẽ trong C++ cho phép mã linh hoạt và mở rộng. Bằng cách sử dụng các hàm ảo và hàm ảo đơn, bạn có thể tạo ra các hệ thống lớp có thể được sử dụng thay thế nhau, dẫn đến mã thêm phân vùng và dễ bảo trì.
Hãy nhớ, như việc học bất kỳ kỹ năng mới nào, việc thành thạo polymorphism cần thực hành. Đừng bỏ cuộc nếu nó không nhấn mạnh ngay lập tức – tiếp tục lập trình, tiếp tục thử nghiệm, và sớm bạn sẽ polymorphing như một chuyên gia!
Credits: Image by storyset