C++ Đa hình với ví dụ
Đa hình trong C++?
In C++, tính đa hình làm cho hàm thành viên hoạt động khác nhau dựa trên đối tượng gọi/gọi nó. Đa hình là một từ tiếng Hy Lạp có nghĩa là có nhiều hình thức. Nó xảy ra khi bạn có một hệ thống phân cấp các lớp liên quan thông qua tính kế thừa.
Ví dụ: giả sử chúng ta có hàm makeSound(). Khi mèo gọi chức năng này, nó sẽ phát ra âm thanh meo meo. Khi một con bò thực hiện chức năng tương tự, nó sẽ phát ra âm thanh kêu.
Mặc dù chúng ta có một chức năng nhưng nó hoạt động khác nhau trong những trường hợp khác nhau. Chức năng có nhiều dạng; do đó, chúng tôi đã đạt được tính đa hình.
Các loại đa hình
C++ hỗ trợ hai loại đa hình:
- Đa hình thời gian biên dịch, và
- Đa hình thời gian chạy.
Biên dịch đa hình thời gian
Bạn gọi các hàm bị quá tải bằng cách khớp số lượng và loại đối số. Thông tin có mặt trong thời gian biên dịch. Điều này có nghĩa là C++ trình biên dịch sẽ chọn đúng chức năng tại thời điểm biên dịch.
Tính đa hình trong thời gian biên dịch đạt được thông qua nạp chồng hàm và nạp chồng toán tử.
Quá tải chức năng
Quá tải hàm xảy ra khi chúng ta có nhiều hàm có tên giống nhau nhưng đối số khác nhau. Các đối số có thể khác nhau về số lượng hoặc loại.
Ví dụ 1
#include <iostream> using namespace std; void test(int i) { cout << " The int is " << i << endl; } void test(double f) { cout << " The float is " << f << endl; } void test(char const *ch) { cout << " The char* is " << ch << endl; } int main() { test(5); test(5.5); test("five"); return 0; }
Đầu ra:
Đây là ảnh chụp màn hình của mã:
Giải thích mã:
- Bao gồm tệp tiêu đề iostream vào mã của chúng tôi. Chúng ta sẽ có thể sử dụng các chức năng của nó.
- Bao gồm không gian tên std trong mã của chúng tôi. Chúng ta sẽ có thể sử dụng các lớp của nó mà không cần gọi nó.
- Tạo một hàm có tên test lấy tham số nguyên i. { đánh dấu sự bắt đầu của phần thân của bài kiểm tra hàm.
- Câu lệnh sẽ được thực thi nếu hàm kiểm tra trên được gọi/gọi.
- Kết thúc phần thân của bài kiểm tra chức năng trên.
- Tạo một hàm có tên test lấy tham số float f. { đánh dấu sự bắt đầu của phần thân của bài kiểm tra hàm.
- Câu lệnh sẽ được thực thi nếu hàm kiểm tra trên được gọi/gọi.
- Kết thúc phần thân của bài kiểm tra chức năng trên.
- Tạo một hàm có tên test lấy tham số ký tự ch. { đánh dấu sự bắt đầu của phần thân của bài kiểm tra hàm.
- Câu lệnh sẽ được thực thi nếu hàm kiểm tra trên được gọi/gọi.
- Kết thúc phần thân của bài kiểm tra chức năng trên.
- Gọi hàm main(). { đánh dấu sự bắt đầu của phần thân hàm.
- Gọi hàm test và truyền 5 cho nó làm giá trị của đối số. Điều này gọi hàm kiểm tra chấp nhận một đối số nguyên, tức là hàm kiểm tra đầu tiên.
- Gọi hàm test và truyền 5.5 cho nó làm giá trị của đối số. Điều này sẽ gọi hàm kiểm tra chấp nhận đối số float, tức là hàm kiểm tra thứ hai.
- Gọi hàm test và truyền số 5 cho nó làm giá trị của đối số. Điều này sẽ gọi hàm kiểm tra chấp nhận đối số ký tự, tức là hàm kiểm tra thứ ba.
- Chương trình phải trả về một giá trị nếu chạy thành công.
- Phần cuối của hàm main().
Chúng ta có ba hàm có cùng tên nhưng có kiểu đối số khác nhau. Chúng tôi đã đạt được tính đa hình.
Operator quá tải
In Operator Quá tải, chúng tôi xác định một ý nghĩa mới cho một C++ toán tử. Nó cũng thay đổi cách toán tử hoạt động. Ví dụ, chúng ta có thể định nghĩa toán tử + để nối hai chuỗi. Chúng ta biết nó là toán tử cộng để cộng các giá trị số. Sau định nghĩa của chúng ta, khi đặt giữa các số nguyên, nó sẽ cộng chúng lại. Khi đặt giữa các chuỗi, nó sẽ nối chúng lại.
Ví dụ 2
#include<iostream> using namespace std; class ComplexNum { private: int real, over; public: ComplexNum(int rl = 0, int ov = 0) { real = rl; over = ov; } ComplexNum operator + (ComplexNum const &obj) { ComplexNum result; result.real = real + obj.real; result.over = over + obj.over; return result; } void print() { cout << real << " + i" << over << endl; } }; int main() { ComplexNum c1(10, 2), c2(3, 7); ComplexNum c3 = c1+c2; c3.print(); }
Đầu ra:
Đây là ảnh chụp màn hình của mã:
Giải thích mã:
- Đưa tệp tiêu đề iostream vào chương trình của chúng tôi để sử dụng các chức năng của nó.
- Bao gồm không gian tên std vào chương trình của chúng tôi để sử dụng các lớp của nó mà không cần gọi nó.
- Tạo một lớp có tên ComplexNum. Dấu { đánh dấu phần đầu của thân lớp.
- Sử dụng công cụ sửa đổi quyền truy cập riêng tư để đánh dấu các biến là riêng tư, nghĩa là chúng chỉ có thể được truy cập từ bên trong lớp.
- Xác định hai biến số nguyên, thực và trên.
- Sử dụng công cụ sửa đổi truy cập công khai để đánh dấu hàm tạo là công khai, nghĩa là nó sẽ có thể truy cập được ngay cả từ bên ngoài tốt nghiệp lớp XNUMX.
- Tạo hàm tạo lớp và khởi tạo các biến.
- Khởi tạo giá trị của biến real.
- Khởi tạo giá trị của biến trên.
- Kết thúc phần thân của hàm tạo.
- Chúng ta cần ghi đè ý nghĩa của toán tử +.
- Tạo kết quả kiểu dữ liệu có kiểu ComplexNum.
- Sử dụng toán tử + với số phức. Dòng này sẽ thêm phần thực của một số vào phần thực của một số khác.
- Sử dụng toán tử + với số phức. Dòng này sẽ thêm phần ảo của một số vào phần ảo của một số khác.
- Chương trình sẽ trả về giá trị của biến result khi thực hiện thành công.
- Kết thúc định nghĩa về ý nghĩa mới của toán tử +, tức là quá tải.
- Gọi phương thức print().
- In số phức mới sau khi cộng vào bảng điều khiển.
- Kết thúc phần thân của hàm print().
- Kết thúc phần thân của lớp ComplexNum.
- Gọi hàm main().
- Truyền các giá trị của cả phần thực và phần phức cần cộng. Phần đầu tiên của c1 sẽ được cộng vào phần đầu tiên của c2, tức là 10+3. Phần thứ hai của c1 sẽ được cộng vào phần thứ hai của c, tức là 2+7.
- Thực hiện một thao tác bằng toán tử + được nạp chồng và lưu kết quả vào biến c3.
- In giá trị của biến c3 trên bàn điều khiển.
- Kết thúc phần thân của hàm main().
Đa hình thời gian chạy
Điều này xảy ra khi phương thức của một đối tượng được gọi/gọi trong thời gian chạy thay vì trong thời gian biên dịch. Tính đa hình trong thời gian chạy đạt được thông qua việc ghi đè hàm. Hàm được gọi/gọi được thiết lập trong thời gian chạy.
Ghi đè chức năng
Ghi đè hàm xảy ra khi một hàm của lớp cơ sở được đưa ra một định nghĩa mới trong lớp dẫn xuất. Khi đó có thể nói hàm cơ sở đã bị ghi đè.
Ví dụ:
#include <iostream> using namespace std; class Mammal { public: void eat() { cout << "Mammals eat..."; } }; class Cow: public Mammal { public: void eat() { cout << "Cows eat grass..."; } }; int main(void) { Cow c = Cow(); c.eat(); return 0; }
Đầu ra:
Đây là ảnh chụp màn hình của mã:
Giải thích mã:
- Nhập tệp tiêu đề iostream vào chương trình của chúng tôi để sử dụng các chức năng của nó.
- Bao gồm không gian tên std vào chương trình của chúng tôi để sử dụng các lớp của nó mà không cần gọi nó.
- Tạo một lớp có tên là Động vật có vú. { đánh dấu sự bắt đầu của nội dung lớp.
- Sử dụng công cụ sửa đổi quyền truy cập công khai để đặt chức năng mà chúng ta sắp tạo thành có thể truy cập công khai. Nó sẽ có thể truy cập được từ bên ngoài lớp này.
- Tạo một hàm public tên là eat. { đánh dấu sự bắt đầu của thân hàm.
- In câu lệnh được thêm vào hàm cout khi hàm eat() được gọi.
- Phần cuối của hàm eat().
- Kết thúc cơ thể của lớp Động vật có vú.
- Tạo một lớp có tên Cow kế thừa lớp Động vật có vú. Bò là lớp dẫn xuất, trong khi Động vật có vú là lớp cơ sở. { đánh dấu sự bắt đầu của lớp này.
- Sử dụng công cụ sửa đổi quyền truy cập công khai để đánh dấu chức năng mà chúng ta sắp tạo là có thể truy cập công khai. Nó sẽ có thể truy cập được từ bên ngoài lớp này.
- Ghi đè hàm eat() đã được xác định trong lớp cơ sở. { đánh dấu sự bắt đầu của thân hàm.
- Câu lệnh in trên bảng điều khiển khi hàm này được gọi.
- Kết thúc phần thân của hàm eat().
- Kết thúc cơ thể của lớp Bò.
- Gọi hàm main(). { đánh dấu sự bắt đầu của phần thân của hàm này.
- Tạo một thể hiện của lớp Cow và đặt tên cho nó là c.
- Gọi hàm eat() được xác định trong lớp Cow.
- Chương trình phải trả về một giá trị sau khi hoàn thành thành công.
- Kết thúc hàm main().
C++ Chức năng ảo
Hàm ảo là một cách khác để triển khai tính đa hình trong thời gian chạy trong C++. Đây là một hàm đặc biệt được định nghĩa trong lớp cơ sở và được định nghĩa lại trong lớp dẫn xuất. Để khai báo một hàm ảo, bạn nên sử dụng từ khóa virtual. Từ khóa phải đặt trước phần khai báo hàm trong lớp cơ sở.
Nếu một lớp hàm ảo được kế thừa, lớp ảo sẽ xác định lại hàm ảo cho phù hợp với nhu cầu của nó. Ví dụ:
#include <iostream> using namespace std; class ClassA { public: virtual void show() { cout << "The show() function in base class invoked..." << endl; } }; class ClassB :public ClassA { public: void show() { cout << "The show() function in derived class invoked..."; } }; int main() { ClassA* a; ClassB b; a = &b; a->show(); }
Đầu ra:
Đây là ảnh chụp màn hình của mã:
Giải thích mã:
- Bao gồm tệp tiêu đề iostream trong mã để sử dụng các chức năng của nó.
- Bao gồm không gian tên std trong mã của chúng tôi để sử dụng các lớp của nó mà không cần gọi nó.
- Tạo một lớp có tên ClassA.
- Sử dụng công cụ sửa đổi truy cập công khai để đánh dấu một thành viên trong lớp là có thể truy cập công khai.
- Tạo một hàm ảo có tên show(). Nó sẽ là một chức năng công cộng.
- Văn bản cần in khi gọi show() được gọi. Cuối cùng là một C++ từ khóa, có nghĩa là dòng cuối cùng. Nó di chuyển con trỏ chuột đến dòng tiếp theo.
- Kết thúc phần thân của hàm ảo show().
- Phần cuối của lớp ClassA.
- Tạo một lớp mới có tên ClassB kế thừa lớp ClassA. ClassA trở thành lớp cơ sở trong khi ClassB trở thành lớp dẫn xuất.
- Sử dụng công cụ sửa đổi truy cập công khai để đánh dấu một thành viên trong lớp là có thể truy cập công khai.
- Xác định lại hàm ảo show() xuất phát từ lớp cơ sở.
- Văn bản cần in trên bảng điều khiển khi hàm show() được xác định trong lớp dẫn xuất được gọi.
- Kết thúc phần thân của hàm show().
- Phần cuối của phần thân của lớp dẫn xuất, ClassB.
- Gọi hàm main(). Logic chương trình nên được thêm vào trong phần thân của nó.
- Tạo một biến con trỏ có tên a. Nó trỏ đến lớp có tên ClassA.
- Tạo một thể hiện của lớp có tên ClassB. Ví dụ được đặt tên b.
- Gán các giá trị lưu trữ tại địa chỉ b cho biến a.
- Gọi hàm show() được định nghĩa trong lớp dẫn xuất. Ràng buộc muộn đã được thực hiện.
- Phần cuối của hàm main().
Đa hình thời gian biên dịch Vs. Đa hình thời gian chạy
Dưới đây là những khác biệt chính giữa hai:
Tính đa hình thời gian biên dịch | Đa hình thời gian chạy |
---|---|
Nó còn được gọi là đa hình liên kết sớm hoặc đa hình tĩnh | Nó còn được gọi là liên kết muộn/động hoặc đa hình động |
Phương thức này được gọi/gọi trong thời gian biên dịch | Phương thức này được gọi/gọi trong thời gian chạy |
Được thực hiện thông qua nạp chồng hàm và nạp chồng toán tử | Được triển khai thông qua ghi đè phương thức và các hàm ảo |
Ví dụ, nạp chồng phương thức. Nhiều phương thức có thể có tên giống nhau nhưng số lượng hoặc loại đối số khác nhau | Ví dụ, ghi đè phương thức. Nhiều phương thức có thể có tên giống nhau và cùng nguyên mẫu. |
Thực thi nhanh hơn vì việc khám phá phương thức được thực hiện trong thời gian biên dịch | Thực thi chậm hơn do trình khám phá phương thức được thực hiện trong thời gian chạy. |
Less tính linh hoạt để giải quyết vấn đề được cung cấp vì mọi thứ đều được biết trong thời gian biên dịch. | Có nhiều tính linh hoạt để giải quyết các vấn đề phức tạp vì các phương pháp được phát hiện trong thời gian chạy. |
Tổng kết
- Đa hình có nghĩa là có nhiều hình thức.
- Nó xảy ra khi có một hệ thống phân cấp các lớp liên quan thông qua kế thừa.
- Với tính đa hình, một hàm có thể hoạt động khác nhau dựa trên đối tượng gọi/gọi nó.
- Trong đa hình thời gian biên dịch, hàm được gọi được thiết lập trong thời gian biên dịch.
- Trong đa hình thời gian chạy, hàm được gọi được thiết lập trong thời gian chạy.
- Tính đa hình trong thời gian biên dịch được xác định thông qua nạp chồng hàm và nạp chồng toán tử.
- Trong nạp chồng hàm, có nhiều hàm có tên giống nhau nhưng đối số khác nhau.
- Các tham số có thể khác nhau về số lượng hoặc loại.
- Trong nạp chồng toán tử, một ý nghĩa mới được định nghĩa cho C++ khai thác.
- Tính đa hình trong thời gian chạy đạt được thông qua việc ghi đè hàm.
- Trong chức năng ghi đè hàm, lớp dẫn xuất đưa ra định nghĩa mới cho hàm được xác định trong lớp cơ sở.