Giao diện
🎭 Virtual Functions — Hàm ảo
virtual là chìa khóa để đạt được runtime polymorphism — gọi đúng method dựa trên actual type của object, không phải declared type. Vấn đề: Method Hiding
cpp
#include <iostream>
class Animal {
public:
void speak() {
std::cout << "Some sound\n";
}
};
class Dog : public Animal {
public:
void speak() {
std::cout << "Woof!\n";
}
};
int main() {
Dog myDog;
Animal* ptr = &myDog; // Base pointer to derived object
ptr->speak(); // ❌ Output: "Some sound" — KHÔNG phải "Woof!"
}Vấn đề: Compiler quyết định gọi method nào dựa trên declared type (Animal*), không phải actual type (Dog).
Giải pháp: virtual Keyword
cpp
#include <iostream>
class Animal {
public:
virtual void speak() { // ✅ Thêm virtual
std::cout << "Some sound\n";
}
};
class Dog : public Animal {
public:
void speak() override { // ✅ override (C++11)
std::cout << "Woof!\n";
}
};
class Cat : public Animal {
public:
void speak() override {
std::cout << "Meow!\n";
}
};
int main() {
Dog myDog;
Cat myCat;
Animal* ptr1 = &myDog;
Animal* ptr2 = &myCat;
ptr1->speak(); // ✅ "Woof!" — runtime dispatch
ptr2->speak(); // ✅ "Meow!" — runtime dispatch
}override Keyword (C++11)
override không bắt buộc, nhưng HIGHLY RECOMMENDED:
cpp
class Animal {
public:
virtual void speak() const { }
};
class Dog : public Animal {
public:
// ❌ Bug: quên 'const' — tạo method mới, không override!
void speak() { }
// ✅ Với override, compiler check cho bạn
void speak() override { } // ❌ Error: no matching base method
// ✅ Correct
void speak() const override { }
};📌 HPN Standard
LUÔN dùng override khi override virtual method. Compiler sẽ bắt lỗi nếu bạn không thực sự override gì cả.
final Keyword (C++11)
Ngăn Override thêm
cpp
class Animal {
public:
virtual void speak() { }
};
class Dog : public Animal {
public:
void speak() final { // ✅ Không ai được override nữa
std::cout << "Woof!\n";
}
};
class Bulldog : public Dog {
public:
// ❌ Error: speak is marked final
// void speak() override { }
};Ngăn Inheritance
cpp
class Singleton final { // ✅ Không ai được kế thừa class này
public:
static Singleton& instance();
};
// ❌ Error: Singleton is final
// class MySingleton : public Singleton { };Virtual Destructor — CRITICAL!
Khi delete object qua base pointer, PHẢI có virtual destructor:
cpp
#include <iostream>
class Base {
public:
Base() { std::cout << "Base constructed\n"; }
~Base() { std::cout << "Base destroyed\n"; } // ❌ Non-virtual
};
class Derived : public Base {
int* data_;
public:
Derived() : data_(new int[100]) {
std::cout << "Derived constructed\n";
}
~Derived() {
delete[] data_;
std::cout << "Derived destroyed\n";
}
};
int main() {
Base* ptr = new Derived();
delete ptr; // ❌ MEMORY LEAK! Derived destructor không được gọi!
}Output:
Base constructed
Derived constructed
Base destroyed ← Derived::~Derived() KHÔNG được gọi!Fix: Virtual Destructor
cpp
class Base {
public:
virtual ~Base() { // ✅ Virtual destructor
std::cout << "Base destroyed\n";
}
};
class Derived : public Base {
int* data_;
public:
~Derived() override { // ✅ override
delete[] data_;
std::cout << "Derived destroyed\n";
}
};
int main() {
Base* ptr = new Derived();
delete ptr; // ✅ Cả Derived và Base destructor đều được gọi!
}Output:
Derived destroyed
Base destroyed⚠️ RULE OF THUMB
Nếu class có ít nhất một virtual method, destructor PHẢI là virtual!
Cách Virtual Functions hoạt động: vtable
┌─────────────────────────────────────────────────────────────────┐
│ HOW VIRTUAL WORKS │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Mỗi class có virtual function → Có một VTABLE │
│ │
│ Animal vtable: Dog vtable: │
│ ┌────────────────┐ ┌────────────────┐ │
│ │ speak() ────────┼───→ │ speak() ────────┼───→ Dog::speak │
│ └────────────────┘ └────────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ Animal::speak() Dog::speak() │
│ │
│ Object Layout: │
│ ┌─────────────────────┐ │
│ │ vptr ─────────────────┼───→ vtable │
│ ├─────────────────────┤ │
│ │ member variables │ │
│ └─────────────────────┘ │
│ │
│ Runtime: ptr->speak() → vptr → vtable[0] → correct speak() │
│ │
└─────────────────────────────────────────────────────────────────┘Chi phí của Virtual:
- Mỗi object có thêm vptr (8 bytes on 64-bit)
- Indirect function call (cache miss có thể xảy ra)
- Nhưng đây là giá rất nhỏ cho flexibility!
Covariant Return Types
Virtual function có thể return derived type:
cpp
class Animal {
public:
virtual Animal* clone() const {
return new Animal(*this);
}
};
class Dog : public Animal {
public:
Dog* clone() const override { // ✅ Return Dog*, không phải Animal*
return new Dog(*this);
}
};📚 Tổng kết
| Keyword | Meaning |
|---|---|
virtual | Enable runtime dispatch |
override | Verify override at compile time |
final | Prevent further override |
| Virtual destructor | Required if deleting via base pointer |
| vtable | Runtime lookup table cho virtual methods |
➡️ Tiếp theo
Tiếp theo: Polymorphism — Sức mạnh của runtime polymorphism.