[OOP] Hàm ảo (Virtual function), override và final

Hàm ảo – Virtual function

Trong bài con trỏ và tham chiếu của Base class đến đối tượng Derived ta có thể sử dụng con trỏ, reference của Base class thay vì sử dụng trực tiếp đối tượng của từng lớp dẫn suất để code đơn giản hơn. Tuy nhiên gặp phải vấn đề là con trỏ, reference của Base class chỉ gọi đến các hàm của Base class, mà không thể gọi đến các hàm của lớp dẫn suất. Để giải quyết vấn đề này C++ đưa ra khái niệm hàm ảo (virtual function).

Virtual function là 1 dạng đặc biệt của hàm cho phép ta gọi hàm của lớp dẫn suất thông qua con trỏ, reference của lớp cơ sở. Đó cũng thể hiện tính đa hình (polymorphism) trong lập trình hướng đối tượng.

Virtual function được định nghĩa lại trong lớp dẫn suất gọi là ghi đè (override). Hàm override trong lớp dẫn suất phải có cùng tên, cùng tham số và cùng dữ liệu trả về với virtual function trong Base class.

Để định nghĩa 1 virtual function ta dùng từ khóa virtual.

Ví dụ:


#include <iostream>

using namespace std;

class Base

{

public:

   virtual void Info()

   {

      cout << "Day la ham Info Base class" << endl;

   }

};

class  Derived : public Base

{

public:

   void Info()

   {

      cout << "Day la ham Info Derived class" << endl;

   }

};

int main()

{

   Derived derived;

   derived.Info();

   //Tham chieu base class den derived object
   Base& rbase = derived;

   //Goi ham Info cua Derived class
   rbase.Info();

   return 0;

}

Kết quả:

Day la ham Info Derived class
Day la ham Info Derived class

Ở ví dụ trên hàm Info trong Base class được đánh dấu là virtual. Trong lớp Derived ta override lại hàm Info. rbase là tham chiếu của Base class đến đối tượng của Derived, nên khi ta gọi hàm Info thông qua rbase, nó sẽ gọi chính xác hàm Info trong class Derived – đối tượng mà rbase tham chiếu tới.

Chú ý:

Luôn định nghĩa hàm hủy của Base class là virtual để khi hủy tham chiếu, con trỏ của Base class đến đối tượng của Derived thì hàm hủy của Derived chắc chắn được gọi.

Ví dụ:


#include <iostream>

using namespace std;

class Base

{

public:

   ~Base()

   {

      cout << "This is base destructor" << endl;

   }

};

class  Derived : public Base

{

public :

   ~Derived()

   {

      cout << "This is derived destructor" << endl;

   }

};

int main()

{

   Base* base = new Derived();

   delete base;

   return 0;

}

Kết quả:

This is base destructor

Ở ví dụ trên hàm hủy của Base class không được định nghĩa là virtual nên khi ta hủy con trỏ base hàm hủy của Drived không được gọi. Nên ta định nghĩa hàm hủy của Base class là virtual.


#include <iostream>

using namespace std;

class Base

{

public:

   virtual ~Base()

   {

      cout << "This is base destructor" << endl;

   }

};

class  Derived : public Base

{

public :

   ~Derived()

   {

      cout << "This is derived destructor" << endl;

   }

};

int main()

{

   Base* base = new Derived();

   delete base;

   return 0;

}

Kết quả:

This is derived destructor
This is base destructor

Override và final

Như chúng ta đã biết để lớp dẫn suất override 1 virtual function của Base class thì 2 hàm phải có cùng tên, cùng tham số và cùng kiểu dữ liệu trả về. Tuy nhiên trong nhiều trường hợp ta có thể xảy ra nhầm lẫn khi override 1 virtual function.

Ví dụ:


class Base

{

public:

   virtual void Info()

   {

      cout << "Day la ham Info Base class" << endl;

   }

};

class  Derived : public Base

{

public:

   void Info() const

   {

      cout << "Day la ham Info Derived class" << endl;

   }

};

Trong ví dụ trên hàm Derived::Info KHÔNG override hàm Base::Info vì hàm Derived::Info là const còn hàm Base::Info thì không phải.

Trong C++ 11 cung cấp cho ta từ khóa override để kiểm tra xem hàm đó có được override từ Base class không. Nếu không override virtual function của Base class trình biên dịch sẽ thông báo lỗi.

Ví dụ :


//Error
void Info() const override

{

   cout << "Day la ham Info Derived class" << endl;

}

//Correct
void Info() override

{

   cout << "Day la ham Info Derived class" << endl;

}

Trong nhiều trường hợp ta không muốn lớp dẫn suất override 1 virtual function trong Base class. C++ 11 cung cấp cho ta từ khóa final để thực hiện điều này. Virtual function được đánh dấu là final sẽ không cho phép override ở lớp dẫn suất. Nếu lớp dẫn suất vẫn override thì trình biên dịch sẽ báo lỗi.

Ví dụ :


class Base

{

public:

   virtual void Info() final

   {

      cout << "Day la ham Info Base class" << endl;

   }

};

class  Derived : public Base

{

public:

   //Error
   void Info() override

   {

      cout << "Day la ham Info Derived class" << endl;

   }

};

Was this article helpful?

Leave A Comment?