Chi tiết bài học Hàm ảo trong C++

Hàm ảo trong C++

Trong bài này bạn sẽ được học về hàm ảo và nơi sử dụng nó. Ngoài ra, bạn cũng sẽ được học về hàm ảo thuần và lớp trừu tượng .

Một hàm ảo là một hàm thành viên trong lớp chính mà bạn cần định nghĩa lại trong lớp kế thừa.

Trước khi tìm hiểu và khám phá kỹ hơn, cùng tìm hiểu và khám phá về nguyên do tại sao hàm ảo lại được cần đến .

Một ví dụ để bắt đầu

Giả sử rằng, tất cả chúng ta đang thao tác với một game show ( đơn cử là có vũ khí ) .
Chúng ta tạo ra lớp Weapon ( Vũ khí ) và hai lớp thừa kế Bomb ( Bom ) và Gun ( Súng ) để nạp những tính năng cho những vũ khí đó .

#include 
using namespace std;

class Weapon
{
    public:
       void loadFeatures()
         { cout << "Loading weapon features.\n"; }
};

class Bomb : public Weapon
{
    public:
       void loadFeatures()
         { cout << "Loading bomb features.\n"; }
};

class Gun : public Weapon
{
    public:
       void loadFeatures()
         { cout << "Loading gun features.\n"; }
};

int main()
{
    Weapon *w = new Weapon;
    Bomb *b = new Bomb;
    Gun *g = new Gun;

    w->loadFeatures();
    b->loadFeatures();
    g->loadFeatures();

    return 0;
}

Đầu ra

Loading weapon features .
Loading bomb features .

Loading gun features .

Chúng ta định nghĩa ba đối tượng người dùng con trỏ w, b và g của lớp Weapon, Bomb và Gun. Sau đó, tất cả chúng ta gọi hàm thành viên loadFeatures ( ) của mỗi đối tượng người tiêu dùng sử dụng :

w->loadfeatures();
b->loadFeatures();
g->loadFeatures();

Chạy thành công xuất sắc !
Tuy nhiên, dự án Bất Động Sản game show mở màn trở nên lớn hơn và lớn hơn nữa. Và tất cả chúng ta quyết định hành động rằng phải tạo một lớp Loader riêng để nạp vào tính năng những loại vũ khí .
Lớp Loader này sẽ nạp những tính năng bổ trợ của một loại vũ khi tùy thuộc vào việc vũ khí được chọn là gì .

class Loader
{
   public:
     void loadFeatures(Weapon *weapon)
     {
        weapon->features();
     }     
};

Hàm loadFeatures ( ) sẽ nạp vào tính năng của một vũ khí xác lập .

Cùng thử lập trình lớp Loader của chúng ta

#include 
using namespace std;

class Weapon
{
    public:
      void features()
         { cout << "Loading weapon features.\n"; }
};

class Bomb : public Weapon
{
    public:
       void features()
         { cout << "Loading bomb features.\n"; }
};

class Gun : public Weapon
{
    public:
       void features()
         { cout << "Loading gun features.\n"; }
};

class Loader
{
   public:
     void loadFeatures(Weapon *weapon)
     {
        weapon->features();
     }     
};

int main()
{
    Loader *l = new Loader;
    Weapon *w;
    Bomb b;
    Gun g;

    w = &b
    l->loadFeatures(w);

    w = &g
    l->loadFeatures(w);

    return 0;
}

Đầu ra

Loading weapon features .
Loading weapon features .

Loading weapon features .

Đoạn mã lập trình của tất cả chúng ta có vẻ như đã đúng. Tuy nhiên, tính năng vũ khí được nạp vào 3 lần .
Ban đầu, đối tượng người tiêu dùng Weapon w đang trỏ vào đối tượng người tiêu dùng b ( thuộc lớp Bomb ). Và sau đó tất cả chúng ta cố gắng nỗ lực nạp tính năng của đối tượng người dùng Bomb này bằng cách truyền nó vào hàm loadFeatures ( ) sử dụng đối tượng người tiêu dùng con trỏ l ( thuộc lớp Loader ) .
Tương tự, tất cả chúng ta đã thử nạp vào tính năng của đối tượng người tiêu dùng Gun .
Tuy nhiên, hàm loadFeatures ( ) của lớp Loader nhận con trỏ trỏ tới đối tượng người tiêu dùng của lớp Weapon làm đối số :

void loadFeatures(Weapon *weapon)

Đó là lý do tại sao tính năng vũ khí được nạp tới 3 lần. Để giải quyết vấn đề này, bạn cần biến một hàm thuộc lớp chính (lớp Weapon) thành hàm ảo sử dụng từ khóa virtual.

class Weapon
{
    public:
      virtual void features()
         { cout << "Loading weapon features.\n"; }
};

Ví dụ: Sử dụng hàm ảo để giải quyết vấn đề

#include 
using namespace std;

class Weapon
{
    public:
      virtual void features()
         { cout << "Loading weapon features.\n"; }
};

class Bomb : public Weapon
{
    public:
       void features()
         { cout << "Loading bomb features.\n"; }
};

class Gun : public Weapon
{
    public:
       void features()
         { cout << "Loading gun features.\n"; }
};

class Loader
{
   public:
     void loadFeatures(Weapon *weapon)
     {
        weapon->features();
     }     
};

int main()
{
    Loader *l = new Loader;
    Weapon *w;
    Bomb b;
    Gun g;

    w = &b
    l->loadFeatures(w);

    w = &g
    l->loadFeatures(w);

    return 0;
}

Đầu ra

Loading weapon features .
Loading bomb features .

Loading gun features .

Ngoài ra, cũng nên quan tâm rằng hàm l -> loadFeatures ( w ) sẽ gọi hàm của những lớp khác nhau nhờ vào vào đối tượng người dùng mà đối tượng người tiêu dùng l trỏ tới .
Sử dụng hàm ảo khiến đoạn mã của tất cả chúng ta không chỉ rõ ràng hơn mà còn khả chuyển hơn .
Nếu tất cả chúng ta muốn thêm vào một vũ khí khác ( ví dụ như dao ), tất cả chúng ta hoàn toàn có thể thuận tiện thêm vào và nạp tính năng của nó. Bằng cách nào ư ?

class Knife : public Weapon
{
    public:
       void features()
         { cout << "Loading knife features.\n"; }
};

Và trong hàm main ( )

Knife k; 
w = &k 
l->loadFeatures(w);

Cần quan tâm rằng tất cả chúng ta không hề biến hóa thứ gì trong lớp Loader để nạp tính năng của dao .

Lớp trừu tượng và hàm ảo thuần trong C++

Mục đích của lập trình hướng đối tượng người tiêu dùng là chia một yếu tố phức tạp thành những tập nhỏ hơn. Điều này giúp hiểu và xử lý yếu tố theo một cách hiệu suất cao .
Đôi khi, thiết yếu phải sử dụng thừa kế chỉ để có cái nhìn rõ ràng hơn về yếu tố .
Trong C + +, bạn hoàn toàn có thể tạo một lớp trừu tượng mà không hề được khởi tạo ( bạn không hề tạo một đối tượng người dùng của lớp này ). Tuy nhiên, bạn hoàn toàn có thể thừa kế một lớp từ lớp này, và khởi tạo đối tượng người tiêu dùng của lớp thừa kế đó .
Lớp trừu tượng là lớp chính mà không hề được khởi tạo .
Một lớp chứa hàm ảo thuần cũng được gọi là lớp trừu tượng .

Hàm ảo thuần

Một hàm ảo có lời khai báo kết thúc bằng = 0 được gọi là hàm ảo thuần. Ví dụ :

class Weapon
{
    public:
      virtual void features() = 0;
};

Ở đây, hàm ảo thuần là :

virtual void features() = 0

Và lớp Weapon là một lớp trừu tượng .

Ví dụ: Lớp trừu tượng và hàm ảo thuần

#include 
using namespace std;

// lớp trừu tượng
class Shape                   
{
    protected:
       float l;
    public:
       void getData()       
       {
           cin >> l;
       }
       
       // hàm ảo
       virtual float calculateArea() = 0;
};

class Square : public Shape
{
    public:
       float calculateArea()
       {   return l*l;  }
};

class Circle : public Shape
{
    public:
       float calculateArea()
       { return 3.14*l*l; }
};

int main()
{
    Square s;
    Circle c;

    cout << "Enter length to calculate the area of a square: ";
    s.getData();
    cout<<"Area of square: " << s.calculateArea();
    cout<<"\nEnter radius to calculate the area of a circle: ";
    c.getData();
    cout << "Area of circle: " << c.calculateArea();

    return 0;
}

Đầu ra

Enter length to calculate the area of a square : 4
Area of square : 16
Enter radius to calculate the area of a circle : 5

Area of circle : 78.5

Trong chương trình này, hàm ảo thuần virtual float area ( ) = 0 ; được định nghĩa trong lớp Shape .
Một điều quan trọng cần quan tâm đó là, bạn nên ghi đè hàm ảo thuần của lớp chính trong lớp thừa kế. Nếu bạn không làm vậy, lớp thừa kế cũng sẽ trở thành một lớp trừu tượng .