Bảng ảo
Bảng ảo (hoặc Vtable) là một cơ chế được trình biên dịch C++ sử dụng để hỗ trợ tính đa hình động. Trong đa hình động, hàm thích hợp được gọi trong thời gian chạy, tùy thuộc vào loại đối tượng thực tế.
Khi một lớp chứa một hàm ảo, trình biên dịch sẽ tạo một bảng ảo cho lớp đó. Bảng này chứa các con trỏ hàm tới các hàm ảo được định nghĩa trong lớp. Mỗi đối tượng của lớp đó có một con trỏ tới bảng ảo của nó (vptr, con trỏ ảo), được trình biên dịch tự động khởi tạo trong quá trình xây dựng đối tượng.
Ví dụ
Hãy xem xét ví dụ sau:
class Base {
public:
virtual void function1() {
std::cout << "Base::function1" << std::endl;
}
virtual void function2() {
std::cout << "Base::function2" << std::endl;
}
};
class Derived : public Base {
public:
void function1() override {
std::cout << "Derived::function1" << std::endl;
}
void function3() {
std::cout << "Derived::function3" << std::endl;
}
};
int main() {
Base* obj = new Derived(); // tạo một đối tượng Derived và gán một con trỏ kiểu Base*
obj->function1(); // gọi Derived::function1, do tính đa hình động
obj->function2(); // gọi Base::function2
delete obj;
return 0;
}
Trong ví dụ này, khi một đối tượng Derived được tạo, trình biên dịch sẽ tạo một Vtable cho lớp Derived, chứa các con trỏ tới các hàm ảo của nó:
- Derived::function1 (được ghi đè từ Base)
- Base::function2 (kế thừa từ Base)
Con trỏ vptr trong đối tượng Derived trỏ tới Vtable này. Khi function1 được gọi trên con trỏ base đến đối tượng Derived, con trỏ hàm trong Vtable được sử dụng để gọi đúng hàm (trong trường hợp này là Derived::function1). Tương tự, lệnh gọi fuction2 gọi Base::function2, vì đó là con trỏ hàm được lưu trữ trong Vtable cho lớp Derived.
Lưu ý rằng function3 không phải là một phần của Vtable, vì nó không phải là một hàm ảo.