Tính đa hình trong oop

     

Đa hình là gì?

Đa hình là 1 trong trong bốn đặc điểm đặc trưng của lập trình hướng đối tượng sát bên tính đóng góp gói, tính trừu tượng và tính kế thừa. Vậy thì nhiều hình là gì?

Đa hình (polymorphism) là hiện tượng lạ mà các đối tượng người dùng thuộc các class không giống nhau rất có thể biểu diễn cùng một thông thiệp theo các cách khác nhau. Tương đối nặng về kim chỉ nan một chút nhưng mà xem lấy ví dụ sau các bạn sẽ rõ ngay!


*
Sơ thứ Class

Dựa trên sơ đồ đang xây dựng, mình vẫn code các class như sau:

class NhanVienprotected: string hoTen; float luong;public: NhanVien() this->hoTen = ""; this->luong = 0.0; void nhap() cout hoTen); void xuat() cout hoTen class NhanVienSanXuat : public NhanVienprivate: int soSanPham; float tienCong1SP;public: NhanVienSanXuat() : NhanVien() this->soSanPham = 0; this->tienCong1SP = 0; void nhap() NhanVien::nhap(); cout > this->soSanPham; cout > this->tienCong1SP; void xuat() cout soSanPham tienCong1SP luong luong = this->soSanPham * this->tienCong1SP; ;class NhanVienVanPhong : public NhanVienprivate: float luongCoBan; int soNgayLamViec;public: NhanVienVanPhong() : NhanVien() this->luongCoBan = 0.0; void nhap() NhanVien::nhap(); cout > this->luongCoBan; cout > this->soNgayLamViec; void xuat() NhanVien::xuat(); cout luongCoBan soNgayLamViec luong luong = this->soNgayLamViec * this->luongCoBan; ;class CongTyprivate: vector NVVP; vector NVSX;public: void nhap() cout > n; for (int i = 0; i NVVP.push_back(nv); cout > m; for (int i = 0; i NVSX.push_back(nv); void xuat() cout NVVP.size(); i++) cout NVVP.at(i).xuat(); cout NVSX.size(); i++) cout NVSX.at(i).xuat(); void tinhLuong() for (int i = 0; i NVVP.size(); i++) this->NVVP.at(i).tinhLuong(); for (int i = 0; i NVSX.size(); i++) this->NVSX.at(i).tinhLuong(); ;Nhìn vào phần đa đoạn code trên, chúng ta cũng có thể dễ dàng nhận ra rằng, tuy đa số là hành động nhập, xuất với tính lương, mặc dù nhiên bọn họ lại đề nghị gọi phương thức này mang lại 2 đối tượng thuộc kiểu không giống nhau là NVVP và NVSX. Còn một điều nữa là tuy phần đông là nhân viên nhưng lại phải dùng 2 vector không giống nhau để tàng trữ 2 đối tượng người sử dụng này.

Bạn đang xem: Tính đa hình trong oop

Câu hỏi đề ra là liệu gồm cách làm sao để hoàn toàn có thể lưu trữ 2 loại nhân viên cấp dưới này trong và một vector? Và phương thức nhập, xuất, tính lương bao gồm thể tự động biết nó thực hiện hành động cho đối tượng người tiêu dùng nào để thực hiện cho đúng không? Câu trả lời là bao gồm và nó được tiến hành thông qua cách làm ảo. Vậy thì nên cùng tìm hiểu phương thức ảo là gì?

Phương thức ảo

Phương thức ảo (virtual method) trong C++ là cách thể hiện tính nhiều hình trong xây dựng hướng đối tượng của C++, các phương thức sinh hoạt class cơ sở tất cả tính nhiều hình phải được định nghĩa là 1 phương thức ảo.

Và nhằm khai báo một thủ tục ảo, ta khai báo như thông thường nhưng thêm trường đoản cú khóa “virtual” phía trước.

class protected: virtual (<>) ;Ví dụ như trong việc ở trên, các phương thức tính lương, nhập cùng xuất đều sở hữu tính nhiều hình do so với hai đối tượng người sử dụng NVSX và NVVP thì sẽ sở hữu cách triển khai phương thức không giống nhau. Vì đó, mình sẽ chỉnh sửa 3 cách làm này ngơi nghỉ class dẫn xuất thành phương thức ảo như sau:

class NhanVienpublic: virtual void nhap() // code goes here... virtual void xuat() // code goes here... virtual void tinhLuong() // code goes here... ;Chúng ta vẫn có các phương thức ảo, vậy sự việc hiện trên là làm thế nào để chương trình biết phương thức của đối tượng người tiêu dùng nào để thực hiện cho đúng? Thì trong C++, tính nhiều hình được thể hiện thông qua tham chiếu và nhỏ trỏ. Ví dụ như sau:

Đối với tham chiếu, đối tượng người sử dụng tham chiếu của class cơ sở hoàn toàn có thể tham chiếu đến đối tượng người dùng thuộc class dẫn xuất. Thời điểm này, lúc gọi cách tiến hành ảo, công tác sẽ gọi đúng thủ tục của đối tượng người sử dụng mà thay đổi tham chiếu tham chiếu tới. Ví dụ:

NhanVienVanPhong nvvp;NhanVien &nv = nv; // đổi thay nv tham chiếu đến đổi thay nvvpnv.nhap(); // thủ tục được call là sẽ cách làm nhập của class NhanVienVanPhongDo để tham chiếu đến một biến, yêu cầu biến kia đề nghị tồn trên trước, cho nên vì vậy cách tham chiếu khôn cùng ít khi được thực hiện mà nỗ lực vào đó, bạn ta sẽ dùng bé trỏ.

Trong bài Kế quá trong C++, mình đã có nói con trỏ của class cơ sở rất có thể trỏ đến đối tượng của class dẫn xuất, tính nhiều hình trong C++ đa phần đều biểu thị qua biện pháp này. Cũng tương tự như việc tham chiếu, tiến hành qua con trỏ như sau:

NhanVien *nv = new NhanVienVanPhong; // nhỏ trỏ nv trỏ tới dịch chuyển kiểu NhanVienVanPhongnv->nhap(); // cách tiến hành được gọi là sẽ cách thức nhập của class NhanVienVanPhongQuay quay trở về với vấn đề ban đầu, bây giờ chúng ta đã có thể trả lời hai câu hỏi. Để lưu trữ 2 đối tượng người dùng mà chỉ sử dụng một vector họ sẽ sử dụng con trỏ trỏ đến đối tượng người tiêu dùng thuộc class dẫn xuất. Những phương thức rất có thể được gọi theo đúng đối tượng người tiêu dùng thông qua nhỏ trỏ cơ mà vector lưu giữ trữ. Bây giờ chúng ta đang sửa lại như sau:

// Thayvector NVVP;vector NVSX;// sinh hoạt class CongTy Bằngvector NV;Do trực thuộc tính ráng đối, các phương thức có tương quan cũng thay đổi theo, ta đang sửa lại các phương thức của class CongTy không cần triển khai trên nhì vector khác nhau, hai đối tượng khác nhau nữa, bọn họ sẽ áp dụng tính đa hình, code như sau:

void nhap() cout > n; for (int i = 0; i > k; NhanVien *nv; // Tùy vào người tiêu dùng chọn đối tượng nào nhằm nhập if (k == 1) nv = new NhanVienVanPhong; else nv = new NhanVienSanXuat; nv->nhap(); // ta sẽ thực hiện hàm nhập của đối tượng người sử dụng mà người tiêu dùng chọn this->NV.push_back(nv); }void xuat() cout NV.size(); i++) cout NV.at(i)->xuat(); // tùy vào đối tượng người sử dụng là gì mà cách thức xuất sẽ được gọi theo đúng đối tượng đó void tinhLuong() for (int i = 0; i NV.size(); i++) this->NV.at(i)->tinhLuong(); // tùy vào đối tượng người sử dụng là gì mà cách thức tính lương sẽ tiến hành gọi theo đúng đối tượng người dùng đóCơ chế hoạt động vui chơi của phương thức ảo là dựa trên liên kết động, có thể hiểu link động là đối tượng người dùng không được xác định ví dụ khi biên dịch nhưng mà chỉ được xác minh trong lúc công tác thực thi.

Nói sang một chút về phong thái sử dụng tính nhiều hình với hàm. đưa sử mình thích tính lương độc lập cho một nhân viên, không rõ ràng nhân viên nào mà lại sẽ tùy trực thuộc vào nhân viên bạn có nhu cầu tính, mình đã viết hàm như sau:

// giải pháp 1: tham chiếuvoid tinhLuong(NhanVien &nv) nv.tinhLuong();// giải pháp 2: nhỏ trỏ (nên dùng)void tinhLuong(NhanVien *nv) nv->tinhLuong();Rất thuận lợi phải không, rứa vì việc phải viết nhị hàm để call cho đúng thủ tục theo từng đối tượng khác nhau.

Lưu ý: tính nhiều hình chỉ áp dụng được trải qua tham số là tham chiếu hoặc bé trỏ, nếu khách hàng sử dụng một tham số bình thường, thủ tục của class cơ sở sẽ được gọi vì chưng về bản chất nó là một đối tượng thuộc kiểu class cơ sở.

void tinhLuong(NhanVien nv) nv.tinhLuong(); // thông số nv ở trong class NhanVien bắt buộc phương thức tính lương của class NhanVien sẽ được gọi

Phương thức thuần ảo

Nếu như đối chiếu kỹ thêm 1 chút, bạn sẽ thấy là class nhân viên cấp dưới thì thủ tục tính lương ko có chính vì ta quan trọng tính lương mang đến một nhân viên mà đo đắn là nhân viên cấp dưới gì. Các class dẫn xuất của chính nó là một ví dụ hóa của class đại lý nhân viên, cần ta rất có thể tính lương được, ta biết cách tính cho từng loại nhân viên như vậy nào.

Xem thêm: Cách Làm Sữa Chua Uống Hoa Quả, Cách Làm Sữa Chua Uống Trái Cây

Từ phần đông điều trên, ta gồm khái niệm cách thức thuần ảo. Thủ tục thuần ảo (pure virtual method) là thủ tục ảo không tồn tại phần khái niệm và cần phải được override nghỉ ngơi class dẫn xuất. Để khai báo thủ tục thuần ảo, ta cũng khai báo giống như như cách thức ảo nhưng lại thay vì định nghĩa phần thân hàm, ta sẽ cho nó bằng 0.

class public: virtual (<>) = 0;;Quay lại với bài toán của bọn chúng ta, class nhân viên cấp dưới sẽ không cần phải có hàm tính lương cụ thể do ta lưỡng lự tính thế nào khi không khẳng định được một số loại nhân viên. Với ở class dẫn xuất, họ cần có phương pháp tính lương khác nhau cho từng loại nhân viên, từ đó suy ra phương thức tính lương đang là cách làm thuần ảo. Chúng ta sẽ sửa lại như sau:

class NhanVienpublic: // code goes here... Virtual void tinhLuong() = 0;;Khi mà cách làm tính lương vươn lên là thuần ảo, nghỉ ngơi class dẫn xuất bắt buộc rất cần phải override lại cách thức này. Bọn họ vẫn triển khai override bình thường. Vày ở class dẫn xuất tôi đã override rồi buộc phải không buộc phải sửa gì cả.

Lớp trừu tượng

Lớp trừu tượng (abstract class) là 1 trong class chứa phương thức thuần ảo, bắt buộc tạo một đối tượng người tiêu dùng thuộc lớp trừu tượng. Điều này hiển nhiên, chính vì nếu class cất một hoặc nhiều phương thức ảo, khi đối tượng được tạo thành thì phương thức đó sẽ không tồn tại định nghĩa và sẽ gây nên lỗi.

Một lớp trừu tượng phải có ít nhất một cách thức thuần ảo cùng nó hoàn toàn có thể cùng có các phương thức và phương thức ảo khác. Các phương thức và phương thức ảo trực thuộc lớp trừu tượng vẫn có thể được điện thoại tư vấn từ class dẫn xuất qua toán tử phạm vi (::) như bình thường.

Lớp trừu tượng làm cho logic thực tế trở nên hợp lý và phải chăng hơn vào lập trình. Như đã nói ngơi nghỉ trên, bạn không thể tính lương khi không biết nhân viên đó là nhân viên gì, vị đó, theo logic, ta cần yếu tạo đối tượng người dùng nhân viên được. Giỏi nói đúng hơn, ta không nên chất nhận được người lập trình hoàn toàn có thể tạo ra đối tượng người tiêu dùng nhân viên bằng phương pháp làm cho lớp đó biến đổi lớp thuần ảo.

Vì thủ tục nhập, xuất vẫn không cần override lại trả toàn, vì vậy mình sẽ lưu lại nguyên, chỉ đổi cách thức tính chi phí thành cách thức thuần ảo thôi.

class NhanVienpublic: // Code goes here... Virtual void tinhLuong() = 0;;Lúc này, ngẫu nhiên class nào thừa kế từ class nhân viên đều phải override lại cách tiến hành tính lương. Và chúng ta cũng quan yếu tạo được đối tượng người sử dụng nhân viên nữa. Ví dụ:

class NhanVienKiemToan : public NhanVienpublic: void tinhLuong() // override method tinhLuong // còn nếu không override vẫn nhận thông tin lỗi ;NhanVien nx; // lỗi do không thể tạo đối tượng người tiêu dùng thuộc abstract classLưu ý là con trỏ class nhân viên vẫn rất có thể tạo được thông thường (nếu ko thì sao áp dụng được nhiều hình :D).

Xem thêm: Hủy Lệnh In Của Printer Canon 2900 Đúng Cách Hủy Lệnh In Trên Máy In Canon 2900

Interface

Phần này reviews thêm cho chúng ta thôi chính vì trong C++ không cung ứng sẵn concept interface, chúng ta nên tìm hiểu concept của các ngôn ngữ tiến bộ khác như C#, Java… tuy nhiên ta vẫn hoàn toàn có thể sử dụng concept của những ngôn ngữ khác mang lại C++.

Interface rất có thể được hiểu là 1 trong những class trừu tượng trả toàn, nghĩa là rất nhiều phương thức của interface số đông là cách tiến hành thuần ảo và bạn sẽ cần cần override lại toàn bộ các cách làm của interface sinh sống class dẫn xuất. Ví dụ:

class Animal // Animal là một trong những Interfaceprotected: string sound;public: virtual void move() = 0; virtual void makeNoise() = 0; virtual void eat() = 0;;// Class thừa kế từ Animal đều nên override toàn bộclass Dogpublic: Dog() sound = "Woo - Woo!"; virtual void move() // code goes here... virtual void makeNoise() // code goes here... virtual void eat() // code goes here... ;

Tổng kết

Vậy là trong bài viết này, mình đã reviews cho chúng ta về tính nhiều hình vào C++ và những vấn đề liên quan như phương thức ảo, thuần ảo, lớp trừu tượng với interface. Hi vọng là bài viết có ích với đa số người, đừng quên chia sẻ nội dung bài viết để mọi bạn cùng biết nha. Ví như có bất kỳ thắc mắc nào các bạn hãy để lại bình luận phía dưới mình vẫn phản hồi. Cảm ơn chúng ta đã theo dõi bài xích viết!

Source Code

#include using namespace std;#include #include class NhanVienprotected: string hoTen; float luong;public: NhanVien() this->hoTen = ""; this->luong = 0.0; virtual void nhap() cout hoTen); virtual void xuat() cout hoTen soSanPham = 0; this->tienCong1SP = 0; void nhap() NhanVien::nhap(); cout > this->soSanPham; cout > this->tienCong1SP; void xuat() cout soSanPham tienCong1SP luong luong = this->soSanPham * this->tienCong1SP; ;class NhanVienVanPhong : public NhanVienprivate: float luongCoBan; int soNgayLamViec;public: NhanVienVanPhong() : NhanVien() this->luongCoBan = 0.0; void nhap() NhanVien::nhap(); cout > this->luongCoBan; cout > this->soNgayLamViec; void xuat() NhanVien::xuat(); cout luongCoBan soNgayLamViec luong luong = this->soNgayLamViec * this->luongCoBan; ;class CongTyprivate: vector NV;public: void nhap() cout > n; for (int i = 0; i > k; NhanVien *nv; // Tùy vào người dùng chọn đối tượng người tiêu dùng nào nhằm nhập if (k == 1) nv = new NhanVienVanPhong; else nv = new NhanVienSanXuat; nv->nhap(); // ta sẽ áp dụng hàm nhập của đối tượng người sử dụng mà người dùng chọn this->NV.push_back(nv); void xuat() cout NV.size(); i++) cout NV.at(i)->xuat(); // tùy vào đối tượng người dùng là gì mà phương thức xuất sẽ tiến hành gọi theo đúng đối tượng người dùng đó void tinhLuong() for (int i = 0; i NV.size(); i++) this->NV.at(i)->tinhLuong(); // tùy vào đối tượng người tiêu dùng là gì mà phương thức tính lương sẽ được gọi theo đúng đối tượng người sử dụng đó };int main() CongTy cty; cty.nhap(); cty.tinhLuong(); cty.xuat(); return 0;