Virtual Trong C++

Chúng tôi rất vui mừng được chia sẻ kiến thức sâu sắc về từ khóa Virtual c la gi và hy vọng rằng nó sẽ hữu ích cho bạn đọc. Bài viết tập trung trình bày ý nghĩa, vai trò và ứng dụng của từ khóa này trong việc tối ưu hóa nội dung trang web và chiến dịch tiếp thị trực tuyến. Chúng tôi cung cấp các phương pháp tìm kiếm, phân tích và lựa chọn từ khóa phù hợp, cùng với các chiến lược và công cụ hữu ích. Hy vọng rằng thông tin mà chúng tôi chia sẻ sẽ giúp bạn xây dựng chiến lược thành công và thu hút lưu lượng người dùng. Xin chân thành cảm ơn sự quan tâm và hãy tiếp tục theo dõi blog của chúng tôi để cập nhật những kiến thức mới nhất.

Ở bài này, tất cả chúng ta sẽ tìm hiểu virtual trong C++. Từ khoá virtual có một số đặc tính khá thú vị mà mình muốn san sẻ với những bạn qua nội dung bài viết ngày hôm nay. Hãy cùng Techacademy tìm hiểu nhé.

Bạn Đang Xem: Virtual Trong C++

1. Virtual Trong C++ Là Gì ? Tác Dụng Của Virtual Trong C++

Một số tài liệu có viết công dụng của Virtual Function như sau:

“Virtual Function là để khai báo một function ở class cha (base class) mà sau đó các class thừa hưởng (derived class) có thể override function đó”

Nhưng chờ đã, có gì không ổn tại phần này, nếu chỉ là để override thôi thì mình hoàn toàn có thể khai báo function ở base class mà không cần virtual thì vẫn được nhưng mà. Vậy ko lẽ đồng chí Virtual Function này vô dụng? Để làm rõ vấn đề cũng như hạn chế buồn ngủ vì phải đọc quá nhiều chữ, tất cả chúng ta thử xét ví dụ nhỏ sau:

class Buffalo { public: void action(){printf(“I’m eating grassn”);}; }; class YoungBuffalo : public Buffalo { void action(){printf(“I’m typing keyboardn”);}; }; int main() { Buffalo *elon = new Buffalo(); YoungBuffalo *andy = new YoungBuffalo(); elon->action(); andy->action(); }

Output sẽ ra như vậy này:

I’m eating grass I’m typing keyboard

Nếu chỉ xét đến đây thì cậu virtual chắc sẽ hơi buồn vì mọi chuyện có vẻ vẫn ổn mà không cần tới việc có mặt của nó. Vì vậy tất cả chúng ta thử xét tiếp 1 ví dụ khác để làm chỗ cho virtual toả sáng một tí.

class Buffalo { public: void action(){printf(“I’m eating grassn”);}; }; class YoungBuffalo : public Buffalo { public: void action(){printf(“I’m typing keyboardn”);}; }; int main() { Buffalo *elon = new Buffalo(); Buffalo *andy = new YoungBuffalo(); // khác với lúc nãy là YoungBuffalo *andy = new YoungBuffalo(); elon->action(); andy->action(); }

Lần này output sẽ là như vậy này:

I’m eating grass I’m eating grass

Đến đây thì chắc không cần thiết phải quá tinh mắt bạn đã và đang nhận ra vấn đề rồi đúng không ạ. Mặc dù andy được tạo ra từ constructor của class YoungBuffalo thế nhưng nó hành xử lại như thể nó là một Buffalo. Thế nhưng ví dụ này trông hơi bị thiếu thông minh vì chả mấy ai khai báo Buffalo *andy = new YoungBuffalo(); như này để tự làm khó mình cả. Mình sẽ xét một ví dụ thực tế hơn chút nữa.

class Buffalo { public: void action(){printf(“I’m eating grassn”);}; }; class YoungBuffalo : public Buffalo { public: void action(){printf(“I’m typing keyboardn”);}; }; void takeAnBuffalo(Buffalo* buffalo){ buffalo->action(); } int main() { Buffalo *elon = new Buffalo(); Buffalo *andy = new YoungBuffalo(); takeAnBuffalo(elon); takeAnBuffalo(andy); }

Output sẽ vẫn lại là:

I’m eating grass I’m eating grass

Xem Thêm : Quizlet là gì, cách sử dụng như thế nào?

Lúc này thì vấn đề thực sự đã rõ rồi, vì vậy tất cả chúng ta sẽ fix với vấn đề này với virtual như sau:

class Buffalo { public: virtual void action(){printf(“I’m eating grassn”);}; // thêm virtual vào đó }; class YoungBuffalo : public Buffalo { public: void action(){printf(“I’m typing keyboardn”);}; }; void takeAnBuffalo(Buffalo* buffalo){ buffalo->action(); } int main() { Buffalo *elon = new Buffalo(); Buffalo *andy = new YoungBuffalo(); takeAnBuffalo(elon); takeAnBuffalo(andy); }

Output:

I’m eating grass I’m typing keyboard

Virtual Trong C++ Là Gì ? Tác Dụng Của Virtual Trong C++

2. Pure Virtual Function Trong C++ Là Gì

Hàm thuần ảo (pure virtual function) được sử dụng khi:

  • Không cần sử dụng hàm này trong lớp cơ sở, chỉ phục vụ cho lớp dẫn xuất
  • Lớp dẫn xuất nên phải khái niệm lại hàm thuần ảo

Ví dụ, tất cả chúng ta có một lớp cơ sở là Shape. Các lớp dẫn xuất của lớp Shape là Triangle, Square và Circle. Tất cả chúng ta muốn tính diện tích quy hoạnh của rất nhiều hình này.

Tất cả chúng ta có thể tạo ra một hàm thuần ảo mang tên là calculateArea() trong lớp Shape. Các lớp Triangle, Square và Circle phải khái niệm lại hàm calculateArea() với công thức tính diện tích quy hoạnh khác nhau cho từng hình.

Hàm thuần ảo không có thân hàm và nên phải kết thúc với “= 0”.

class Shape{ public: // creating a pure virtual function virtual void calculateArea() = 0; };

Lưu ý: Cú pháp “= 0” không phải là gán hàm thuần ảo có mức giá trị bằng 0. Nó chỉ là cú pháp cho thấy thêm đó là hàm thuần ảo (pure virtual function).

Pure Virtual Function Trong C++ Là Gì
Pure Virtual Function Trong C++ Là Gì

3. Virtual Destructor Trong C++

Trong một lớp thì Destructor có thể được ghi lại làm hàm ảo còn Constructor thì không được ghi lại là hàm ảo.

virtual Product(); // illegal virtual ~Product(); // legal

Xét một vài ví dụ để làm rõ Virtual Destructor. Giả sử có lớp cha Base và một lớp con Derived được hiện thực như về sau.

Trường hợp 1: Phương thức lớp cha không ghi lại Virtual

Phương thức hủy lớp cha không được ghi lại là hàm ảo:

class Base { public: Base() {}; ~Base() { cout << “Destructor Basen”; }; }; class Derived : public Base { public: Derived() {}; ~Derived() { cout << “Destructor Derivedn”; } }; int main() { Base *b = new Derived(); delete b; return 0; }

Sau khoản thời gian Build và Debug, chỉ có dòng “Destructor Base” được xuất ra, có tức là chỉ phương thức lớp cha được gọi nhưng phương thức của lớp con không được gọi. Dẫn đến có thể gây nên thiếu sót như không thu hồi bộ nhớ các cấp phép động của lớp cha hoặc các thủ tục cần thực hiện trước lúc đối tượng người tiêu dùng được thu hồi.

Xem Thêm : Curve Finance (CRV) là gì? Tìm hiểu thông tin chi tiết về dự án Curve Finance và token CRV

Xét tiếp ví dụ về sau, tương tự như ví dụ trên nhưng có sửa đổi ở lớp Derived

class Base { public: Base() {}; ~Base() { cout << “Destructor Basen”; }; }; class Derived : public Base { private: int* m_array; public: Derived() { this->m_array = new int[1024]; }; ~Derived() { cout << “Destructor Derivedn”; delete this->m_array; } }; int main() { Base *b = new Derived(); delete b; return 0; }

Với lớp con như trên, mặc dù khái niệm phương thức để phóng thích m_array nhưng phương thức của lớp con không được gọi. Có tức là chương tình đã rò rỉ 1024*4 bytes bộ nhớ.

Trường hợp 2: Phương thức lớp cha có ghi lại Virtual

Phương thức lớp cha được ghi lại là phương thức ảo:

class Base { public: Base() {}; virtual ~Base() { cout << “Destructor Basen”; }; }; class Derived : public Base { public: Derived() {}; ~Derived() { cout << “Destructor Derivedn”; } }; int main() { Base *b = new Derived(); delete b; return 0; }

Bulid và Debug thì lớp học xuất ra hai dòng là

Destructor Derived Destructor Base

Như vậy phương thức hủy của lớp con được gọi trước sau đó mới gọi phương thức hủy lớp cha và các thủ tục cấp thiết trước lúc hủy các đối tượng người tiêu dùng đã được thực hiện đầy đủ.

Virtual Destructor Trong C++
Virtual Destructor Trong C++

4. Nhược Điểm Của Các Hàm Ảo

Vì hồ hết thời kì các bạn sẽ muốn các hàm của mình là ảo, vì sao không làm cho tất cả những hàm trở thành ảo? Lời đáp là bởi vì nó không hiệu quả – việc xử lý một cuộc gọi hàm ảo mất nhiều thời kì hơn là xử lý một cuộc gọi thông thường. Hơn nữa, trình biên dịch cũng phải cấp phép một con trỏ phụ cho từng đối tượng người tiêu dùng lớp có một hoặc nhiều hàm ảo.

Nhược Điểm Của Các Hàm Ảo
Nhược Điểm Của Các Hàm Ảo

5. Tại Sao Không Nên Gọi Các Hàm Ảo Từ Các Hàm Tạo Hoặc Hàm Hủy

Ở đây, Bạn không nên gọi các hàm ảo từ các hàm tạo hoặc hàm hủy. Vì sao?

Hãy nhớ rằng khi một lớp Derived được tạo, phần Base được xây dựng trước. Nếu như khách hàng đã gọi một hàm ảo từ hàm tạo cơ sở và phần lớp Derived thậm chí còn không được tạo, thì nó không thể gọi hàm của Derived vì không có đối tượng người tiêu dùng Derived được khởi tạo để gọi hàm. Trong C ++, nó sẽ gọi hàm trong class Base thay thế.

Một vấn đề tương tự tồn tại cho hàm huỷ. Nếu như khách hàng gọi một hàm ảo trong hàm hủy của lớp Cơ sở, nó sẽ luôn gọi hàm của lớp Cơ sở, bởi vì phần Derived của lớp đã trở nên hủy.

Quy tắc: Không bao giờ gọi các hàm ảo từ các hàm tạo hoặc hàm hủy.

Tại Sao Không Nên Gọi Các Hàm Ảo Từ Các Hàm Tạo Hoặc Hàm Hủy
Tại Sao Không Nên Gọi Các Hàm Ảo Từ Các Hàm Tạo Hoặc Hàm Hủy

6. Tại Sao Bạn Nên Khai Báo Một Hàm Hủy Là Ảo

Giả sử có class Parent và class Child thừa hưởng từ Parent.

Ta khái niệm con trỏ: Parent * p = new Child();

Lúc này để tạo ra Child(), thì Parent() phải được tạo ra trước. Khi tất cả chúng ta delete p, thì cả hai đối tượng người tiêu dùng này cũng phải được gọi Destructor. Vậy nếu không khai báo virtual cho hàm Destructor của Parent, thì chỉ Destructor của Parent được gọi, đối tượng người tiêu dùng Child() vẫn còn đó.

Tại Sao Bạn Nên Khai Báo Một Hàm Hủy Là Ảo
Tại Sao Bạn Nên Khai Báo Một Hàm Hủy Là Ảo

You May Also Like

About the Author: v1000

tỷ lệ kèo trực tuyến manclub 789club