Đa Hình Trong C++ – Techacademy

Ở bài này tất cả chúng ta sẽ khám phá thêm một đặc thù nữa của lập trình hướng đối tượng người tiêu dùng đó là tính đa hình trong C + + nhé. Cùng Techcademy khám phá chi tiết cụ thể qua bài viết dưới đây nhé .

1. Tính Đa Hình Trong C++ Là Gì

Đa hình là 1 trong bốn đặc thù đặc trưng của lập trình hướng đối tượng người dùng bên cạnh tính đóng gói, tính trừu tượng và tính thừa kế. Vậy thì đa hình là gì ?
Đa hình ( polymorphism ) là hiện tượng kỳ lạ mà những đối tượng người dùng thuộc những class khác nhau hoàn toàn có thể trình diễn cùng một thông thiệp theo những cách khác nhau. Hơi nặng về kim chỉ nan 1 chút nhưng xem thí dụ sau bạn sẽ rõ ngay !

Ví dụ hai con vật là con chó và con mèo, hai con vật này đều có thể phát ra tiếng nhưng con mèo sẽ kêu “meo meo” còn con chó lại sủa “gâu gâu”. Hành động phát ra tiếng này tuy là một hành động nhưng khi được 2 đối tượng khác nhau là chó và mèo thực hiện thì lại khác nhau.

Tính Đa Hình Trong C++ Là Gì

2. Các Loại Đa Hình Trong C++

Tính đa hình hầu hết được chia thành hai loại :

  • Compile time Polymorphism.
  • Runtime Polymorphism.

Các Loại Đa Hình Trong C++

+ Compile time Polymorphism:

Tính đa hình này được sử dụng bằng cách nạp chồng hàm hoặc nạp chồng toán tử .
Vậy nạp chồng hàm và nạp chồng toán tử là gì ?

Nạp chồng hàm

Nạp chồng hàm ( Function Overloading ) được cho phép sử dụng cùng một tên gọi cho những hàm “ giống nhau ” ( có cùng mục tiêu ). Nhưng khác nhau về kiểu tài liệu tham số hoặc số lượng tham số .
Nạp chồng hàm được cho phép ta khai báo và định nghĩa những hàm trên cùng với một tên gọi .
Chúng ta lấy ví dụ :

#include 
using namespace std;
 
class inDuLieu 
{
   public:
      void hamIn(int i) {
        cout << "In so nguyen: " << i << endl;
      }

      void hamIn(double  f) {
        cout << "In so thuc: " << f << endl;
      }

      void hamIn(string s) {
        cout << "In chuoi: " << s << endl;
      }
};

int main(void)
{
   inDuLieu idl;
 
   // Goi ham hamIn de in so nguyen
   idl.hamIn(1235);
   // Goi ham hamIn de in so thuc
   idl.hamIn(67.02);
   // Goi ham hamIn de in chuoi
   idl.hamIn("Codelearn.io");
 
   return 0;
}

Biên dịch chương trình ta có tác dụng :
Các Loại Đa Hình Trong C++
Trong thí dụ trên, ta chỉ dùng một hàm duy nhất có tên là hamIn ( ) nhưng hoàn toàn có thể dùng được cho 3 trường hợp khác nhau. Đây là một biểu lộ của tính đa hình .

Nạp chồng toán tử

Nạp chồng toán tử ( Operator Overloading ) được dùng để định nghĩa toán tử cho có sẵn trong c + + ship hàng cho tài liệu riêng do bạn tạo ra .
Giả sử có lớp PhanSo và có những phương pháp đo lường và thống kê như Cong, Tru, Nhan, Chia .
Nếu gặp một biểu thức phức tạp, số lượng phép tính nhiều thì việc sử dụng những phương pháp trên khá khó khăn vất vả và hoàn toàn có thể gây rối cho người lập trình. Vì thế ta sẽ nạp chồng lại những toán tử để hoàn toàn có thể tạo một cái nhìn trực quan vào code, giảm thiểu những lỗi sai không đáng có .
Các toán tử hoàn toàn có thể nạp chồng
Các Loại Đa Hình Trong C++
Các toán tử không hề nạp chồng :

. .* :: ?:

Ví dụ :

#include 
using namespace std;

class Box
{
   public:

      double tinhTheTich(void)
      {
         return chieudai * chieurong * chieucao;
      }
      void setChieuDai( double dai )
      {
          chieudai = dai;
      }

      void setChieuRong( double rong )
      {
          chieurong = rong;
      }

      void setChieuCao( double cao )
      {
          chieucao = cao;
      }
      // Nap chong toa tu + de cong hai doi tuong Box.
      Box operator+(const Box& b)
      {
         Box box;
         box.chieudai = this->chieudai + b.chieudai;
         box.chieurong = this->chieurong + b.chieurong;
         box.chieucao = this->chieucao + b.chieucao;
         return box;
      }
   private:
      double chieudai;      // chieu dai cua mot box
      double chieurong;     // Chieu rong cua mot box
      double chieucao;      // Chieu cao cua mot box
};
// ham main cua chuong trinh
int main( )
{
   Box Box1;                // Khai bao Box1 la cua kieu Box
   Box Box2;                // Khai bao Box2 la cua kieu Box
   Box Box3;                // Khai bao Box3 la cua kieu Box
   double thetich = 0.0;     // Luu giu the tich cua mot box tai day
 
   // thong tin chi tiet cua box 1
   Box1.setChieuDai(5); 
   Box1.setChieuRong(2); 
   Box1.setChieuCao(4);
 
   // thong tin chi tiet cua box 2
   Box2.setChieuDai(7); 
   Box2.setChieuRong(6); 
   Box2.setChieuCao(9);
 
   // the tich cua box 1
   thetich = Box1.tinhTheTich();
   cout << "The tich cua Box1 la: " << thetich <
Sau khi chạy chương trình cho tác dụng :
Các Loại Đa Hình Trong C++
Trong ví dụ trên, ta đã nạp chồng lại toán tử cộng. Tính đa hình được bộc lộ qua việc nạp chồng để tính tổng Box1 và Box2 .

+ Runtime Polymorphism:

Các bàn còn nhớ ví dụ tiên phong của bài không .
#include 
using namespace std;

class Mayvitinh{  
   public: 	 	 	
   void show(){
       cout << "mayvitinh" << endl;
   }
}; 
class mayAcer: public Mayvitinh{  	
    public: 	 	 	
    void show(){
        cout << "mayAcer" << endl;
    }
}; 

int main(){
    mayAcer may1; 
    Mayvitinh *tenmay = &may1
    tenmay->show(); 
}

Có thể thấy chương trình sau khi chạy sẽ gọi đến phương thức show() của lớp Mayvitinh, mà không gọi tới phương thức show() của lớp mayAcer.

Vậy để chương trình gọi tới phương pháp show ( ) của lớp mayAcer ta sử dụng hàm ảo virtual như sau :

#include 
using namespace std;

class Mayvitinh{  
   public: 	 	 	
   virtual void show(){
       cout << "mayvitinh" << endl;
   }
}; 
class mayAcer: public Mayvitinh{  	
    public: 	 	 	
    void show(){
        cout << "mayAcer" << endl;
    }
}; 

int main(){
    mayAcer may1; 
    Mayvitinh *tenmay = &may1
    tenmay->show(); 
}

Sau khi biên dịch chương trình sẽ có tác dụng :
Các Loại Đa Hình Trong C++

Trong ví dụ trên mình đã thêm từ khóa virtual vào hàm show() trong lớp cơ sở Mayvitinh.

Từ khóa virtual này dùng để khai báo một hàm là hàm ảo.

Khi khai báo hàm ảo với từ khóa virtual nghĩa là hàm này sẽ được gọi theo loại đối tượng được trỏ (hoặc tham chiếu), chứ không phải theo loại của con trỏ (hoặc tham chiếu). Và điều này dẫn tới kết quả khác nhau:

  • Nếu không khai báo hàm ảo virtual trình biên dịch sẽ gọi hàm tại lớp cở sở
  • Nếu dùng hàm ảo virtual trình biên dịch sẽ gọi hàm tại lớp dẫn xuất

Khi nhận thấy có khai báo virtual trong lớp cơ sở, trình biên dịch sẽ thêm vào mỗi đối tượng của lớp cơ sở và những lớp dẫn xuất của nó 1 con trỏ chỉ tới bảng phương thức ảo (virtual function table). Con trỏ đó có tên là vptr (virtual pointer). Bảng phương thức ảo là nơi chứa các con trỏ chỉ đến đoạn chương trình đã biên dịch ứng với các phương thức ảo.

Mỗi lớp có một bảng phương pháp ảo. Trình biên dịch chỉ lập bảng phương pháp ảo khi mở màn có việc tạo đối tượng người dùng của lớp. Đến lúc chương trình chạy, phương pháp ảo của đối tượng người dùng mới được nối kết và thi hành trải qua con trỏ vptr .

3. Sự Khác Biệt Giữa Tính Đa Hình Và Tính Kế Thừa

Đa hình vs Kế thừa trong OOP

Đa hình là một khả năng của một đối tượng để hành xử theo nhiều cách. Kế thừa là tạo ra một lớp mới bằng cách sử dụng các thuộc tính và phương thức của một lớp hiện có.
 Sử dụng
Đa hình được sử dụng cho các đối tượng để gọi dạng phương thức nào trong thời gian biên dịch và thời gian chạy. Kế thừa được sử dụng để tái sử dụng mã.
Thực hiện
Đa hình được thực hiện trong các phương pháp. Kế thừa được thực hiện trong các lớp.
 Thể loại
Đa hình có thể được chia thành quá tải và ghi đè. Kế thừa có thể được chia thành thừa kế đơn cấp, đa cấp, phân cấp, lai và nhiều kế thừa.

Sự Khác Biệt Giữa Tính Đa Hình Và Tính Kế Thừa

4. Bài Tập Về Tính Đa Hình Trong C++

Ví dụ : Lớp Bus kế thừa từ lớp Car, cả hai lớp này đều định nghĩa phương pháp show ( )

class Car{  
   public: 	 	 	
   void show(); 
}; 
class Bus: public Car{  	
    public: 	 	 	
    void show(); 
};

khi đó, nếu ta khai báo một con trỏ lớp Bus, nhưng lại trỏ vào địa chỉ của một đối tượng người tiêu dùng lớp Car :

Bus myBus; 
Car *ptrCar = &myBus // đúng nhưng khi gọi: 
ptrCar->show();

thì chương trình sẽ gọi đến phương pháp show ( ) của lớp Car ( là kiểu của con trỏ ptrCar ), mà không gọi tới phương pháp show ( ) của lớp Bus ( là kiểu của đối tượng người tiêu dùng myBus mà con trỏ ptrCar đang trỏ tới ) .
Để xử lý yếu tố này, C + + đưa ra một khái niệm là phương pháp trừu tượng. Bằng cách sử dụng phương pháp trừu tượng. Khi gọi một phương pháp từ một con trỏ đối tượng người tiêu dùng, trình biên dịch sẽ xác lập kiểu của đối tượng người tiêu dùng mà con trỏ đang trỏ đến, sau đó nó sẽ gọi phương pháp tương ứng với đối tượng người tiêu dùng mà con trỏ đang trỏ tới .

Khai báo phương thức trừu tượng

Phương thức trừu tượng ( còn gọi là phương pháp ảo, hàm ảo ) được khai báo với từ khoá virtual :

  •  Nếu khai báo trong phạm vi lớp:
virtual  ([]);
  • Nếu định nghĩa ngoài phạm vi lớp:
virtual  ::([]){…}

Ví dụ :

class Car{     
    public: 
          virtual void show(); 
};

là khai báo phương pháp trừu tượng show ( ) của lớp Car : phương pháp không có tham số và không cần giá trị trả về ( void ) .

Lưu ý: 

  • Từ khoá virtual có thể đặt trước hay sau kiểu trả về của phương thức.
  • Với cùng một phương thức được khai báo ở lớp cơ sở lẫn lớp dẫn xuất, chỉ cần dùng từ khoá virtual ở một trong hai lần định nghĩa phương thức đó là đủ: hoặc ở lớp cơ sở, hoặc ở lớp dẫn xuất.
  • Trong trường hợp cây kế thừa có nhiều mức, cũng chỉ cần khai báo phương thức là trừu tượng (virtual) ở một mức bất kì. Khi đó, tất cả các phương thức trùng tên với phương thức đó ở tất cả các mức đều được coi là trừu tượng.
  • Đôi khi không cần thiết phải định nghĩa chồng (trong lớp dẫn xuất) một phương thức đã được khai báo trừu tượng trong lớp cơ sở.

Sử dụng phương thức trừu tượng – đa hình 

Một khi phương thức được khai báo là trừu tượng thì khi một con trỏ gọi đến phương thức đó, chương trình sẽ thực hiện phương thức tương ứng với đối tượng mà con trỏ đang trỏ tới, thay vì thực hiện phương thức của lớp cùng kiểu với con trỏ. Đây được gọi là hiện tượng đa hình (tương ứng bội) trong C++.
Chương trình sau ví dụ về việc sử dụng phương thức trừu tượng: lớp Bus kế thừa từ lớp Car, hai lớp này cùng định nghĩa phương thức trừu tượng show().

  • Khi ta dùng một con trỏ có kiểu lớp Car trỏ vào địa chỉ của một đối tượng kiểu Car, nó sẽ gọi phương thức show() của lớp Car.
  • Khi ta dùng cũng con trỏ đó, trỏ vào địa chỉ của một đối tượng kiểu Bus, nó sẽ gọi phương thức show() của lớp Bus.

Xem ví dụ sau :

#include 
#include 
using namespace std;
/* Định nghĩa lớp */
class Car {
private:
   int  speed;               // Tốc độ  
   string  mark;           // Nhãn hiệu
   float price;               // Giá xe 						
                        // Khởi tạo với các giá trị ngầm định cho các tham số 
public:
   Car();
   Car(int speed, string mark, float price);
   virtual void show();	// Giới thiệu xe, trừu tượng
   int getSpeed() {
      return speed;
   };
   string getMark() {
      return mark;
   };
   float getPrice() {
      return price;
   };

};

/* Khai báo phương thức bên ngoài lớp */
Car::Car() {
   this->speed = 0;
   this->mark = "";
   this->price = 0;

}
Car::Car(int speed, string mark, float price) {
   this->speed = speed;
   this->mark = mark;
   this->price = price;
}

void Car::show() {                // Phương thức hiển thị xe
   cout << "This is a " << mark << " having a speed of  " << speed << "km/h and its price is $" << price << endl;
}

/* Định nghĩa lớp Bus kế thừa từ lớp Car */
class Bus : public Car {
   int label;  	 	// Số hiệu tuyến xe  	
public:
   // Khởi tạo đủ tham số  
   Bus(int speed = 0, string mark = "", float price = 0, int lable = 0);
   void setLabel(int); 	// Gán số hiệu tuyến xe  	 	
   int getLabel();  	// Đọc số hiệu tuyến xe 
   void show();
};

// Cài đặt lớp Bus
Bus::Bus(int speed, string mark, float price, int label) :Car(speed, mark, price) {
   this->label = label;
}
// Định nghĩa nạp chồng phương thức 
void Bus::show() {  	 	 	// Giới thiệu xe bus 
   cout << "This is a bus of type " << getMark() << ", on the line "
      << label << ", having a speed of " << getSpeed()
      << "km / h and its price is $" << getPrice() << endl;
   return;
}

int main() {

   Car *ptrCar, myCar(100, "Ford", 3000);
   Bus myBus(150, "Mercedes", 5000, 27);// Biến đối tượng của lớp Bus
   ptrCar = &myCar  	 	// Trỏ đến đối tượng lớp Car 
   ptrCar->show();  	 	// Phương thức của lớp Car 

   ptrCar = &myBus  	 	// Trỏ đến đối tượng lớp Bus 
   ptrCar->show();  	// Phương thức của lớp Bus return; 
                     // Hàm của lớp Bus 
   system("pause");

   return 0;
}

Chương trình trên hiển thị tác dụng thông tin như sau :

This is a Ford having a speed of  100km/h and its price is $3000
This is a bus of type Mercedes, on the line 27, having a speed of 150km / h and its price is $5000

Bài Tập Về Tính Đa Hình Trong C++


Đánh Giá Chất Lượng Bài Viết

Average rating 0 / 5. Vote count : 0 No votes so far ! Be the first to rate this post.