Interfaces in C++ (Pure virtual functions)
I. Giải thích về Interface
Interface sẽ đưa ra những quy định mà đối tượng (hoặc lớp) cần có, tức là nó chỉ định "phải có những chức năng nào" mà không nói rõ "cách thực hiện những chức năng đó" như thế nào. Các lớp triển khai interface sẽ tự định nghĩa cách cài đặt chi tiết cho những chức năng đó.
Để dễ hiểu hơn thì thông qua một ví dụ có class robot: class này sẽ có những method bắt buộc như: start, stop, left, right. Khi ta tạo robot A có 2 chân và robot B có 4 chân thì những method này sẽ thực hiện theo những cách khác nhau chứ không thể nào mà giống nhau được. Nhưng 2 robot này “bắt buộc” phải có 4 method này.
Interface trong c++ được triển khai bởi sử dụng các lớp trừu tượng (Abstract class)
II. Pure Virtual Function
1. Khái niệm
Một hàm được khai báo ở class base nhưng không có thân hàm. Có cú pháp: virtual void func() = 0
- Đóng vai trò như một bản thiết kế mà mọi class devired phải tuân theo.
- Không thể tạo một object từ một class có chứa Pure Virtual Function (hàm ảo thuần túy). Class này được gọi là Abstract Class.
- Bất kì class devired muốn tạo được object thì phải override toàn bộ hàm ảo thuần túy của class base.
2. Ví dụ
#include <iostream>
#include <string>
#include <map>
using namespace std;
// Abstract Class
class CacheStorage {
public:
// Hàm ảo thuần túy
virtual void write(void) = 0;
virtual void read(void) = 0;
virtual ~CacheStorage() {}
};
// Derived class
class MemoryCache : public CacheStorage {
public:
void write(void) override {
std::cout << "[RAM] Đang ghi vào bộ nhớ đệm ..." << std::endl;
}
void read(void) override {
std::cout << "[RAM] Đang đọc từ bộ nhớ đệm ..." << std::endl;
}
};
class DiskCache : public CacheStorage {
public:
void write(void) override {
std::cout << "[DISK] Đang ghi vào disk..." << std::endl;
}
void read(void) override {
std::cout << "[DISK] Đang đọc từ disk.." << std::endl;
}
};
int main()
{
// CacheStorage Init_my_cache; Don't create object from Abstract class
CacheStorage* myCache;
myCache = new MemoryCache;
myCache->write();
myCache->read();
myCache = new DiskCache;
myCache->write();
myCache->read();
delete myCache;
return 0;
}
Tại sao lại có virtual destructor. Hãy xem một trường hợp sau
- Class MemoryCache có một buffer được cấp phát: char *buffer = new ...
- Dùng con trỏ class base để quản lí:
CacheStorage* ptr = new MemoryCache();
Trả lời
- Nếu không có
virtualthì khi tadelete ptrthì nó chỉ gọiDestructorcủa class base. Từ đó dẫn đếnDestructorcủa classMemoryCachekhông được chạy vàbufferkhông được giải phóng sẽ bị memory leak. - Nếu có
virtualthìDestructorcủa class base sẽ thực hiện tìm kiếm ngược. Nó sẽ gọi hàm hủy của các class derived trước khi gọi hàm hủy của class base.
Ví dụ:
All rights reserved