Pure virtual destructor เป็นเทคนิคทำให้คลาสเป็น **Abstract** พร้อมรับประกัน **Polymorphic Deletion** ทำงานถูกต้อง
ทำไมต้องใช้ Pure Virtual Destructor?
- ทำให้คลาสเป็น Abstract: กันการ instantiate base class โดยตรง
- บังคับ Polymorphic Deletion: ลบผ่าน base pointer ได้ถูกต้อง
- การทำลายแบบ Chain: ~Derived() → ~Base() ต้องมี base destructor body
กฎสำคัญ: Pure Virtual Destructor ต้องมี Definition
class Base {
public:
virtual ~Base() = 0; // Declaration: pure virtual
};
// Definition จำเป็นต้องมี (แม้จะเป็น pure virtual)
Base::~Base() {
cout << "Base::~Base() called\n";
}
หากไม่มี definition → **Linker Error**: `undefined reference to Base::~Base()`
ตัวอย่างครบถ้วน
#include <iostream>
#include <memory>
using namespace std;
class Base {
public:
virtual ~Base() = 0; // Pure virtual destructor
virtual void identify() const = 0;
};
// ต้อง provide definition
Base::~Base() {
cout << "Base destructor called\n";
}
class DerivedA : public Base {
int id;
public:
DerivedA(int i) : id(i) {}
~DerivedA() override { cout << "DerivedA(" << id << ") destructor\n"; }
void identify() const override { cout << "DerivedA(" << id << ")\n"; }
};
class DerivedB : public Base {
string name;
public:
DerivedB(string n) : name(move(n)) {}
~DerivedB() override { cout << "DerivedB(" << name << ") destructor\n"; }
void identify() const override { cout << "DerivedB(" << name << ")\n"; }
};
int main() {
// Base b; // ❌ Error: abstract class
unique_ptr<Base> ptr1 = make_unique<DerivedA>(42);
unique_ptr<Base> ptr2 = make_unique<DerivedB>("test");
ptr1->identify();
ptr2->identify();
cout << "--- Deleting ---\n";
// Destructors called automatically via unique_ptr
// Order: ~DerivedA() -> ~Base(), ~DerivedB() -> ~Base()
return 0;
}
ผลลัพธ์
DerivedA(42) DerivedB(test) --- Deleting --- DerivedA(42) destructor Base destructor called DerivedB(test) destructor Base destructor called
เปรียบเทียบ: Virtual vs Pure Virtual Destructor
| ด้าน | Virtual Destructor | Pure Virtual Destructor |
|---|---|---|
| Syntax | virtual ~Base() {} | virtual ~Base() = 0; + definition |
| Class Abstract? | ไม่ (ถ้าไม่มี pure virtual อื่น) | ใช่ (เสมอ) |
| Instantiate Base ได้? | ได้ | ไม่ได้ |
| Definition required? | ในบรรทัดเดียวได้ | **ต้องแยก** (definition required) |
| ใช้เมื่อ | Base ธรรมดา ต้องการ polymorphic delete | ต้องการบังคับ subclass only + polymorphic delete |
C++11/14/17/20 Syntax
// C++11: default implementation
class Base {
public:
virtual ~Base() = 0;
};
Base::~Base() = default; // Definition
// หรือรวมใน class (C++11)
class Base {
public:
virtual ~Base() = default; // ไม่ใช่ pure virtual แตก็ทำให้เป็น abstract ได้ถ้ามี pure virtual อื่น
};
// Pure virtual destructor แบบเต็ม
class AbstractBase {
public:
virtual void foo() = 0;
virtual ~AbstractBase() = 0;
};
AbstractBase::~AbstractBase() = default; // Definition
Common Mistake
class Base {
public:
virtual ~Base() = 0; // ❌ Missing definition!
};
// Base::~Base() {} // ต้องมี definition นี้
// ไม่งั้น linker error: undefined reference to `Base::~Base()'
เมื่อไหร่ควรใช้ Pure Virtual Destructor?
- ออกแบบ **Interface Class** (มีแต่ pure virtual functions)
- ต้องการ **บังคับ** ให้สร้างได้เฉพาะ derived classes
- ต้องการ **polymorphic deletion** ผ่าน base pointer
- Base class ไม่มี state ของตัวเอง (pure interface)
สรุป
Pure virtual destructor = **Abstract class marker** + **Polymorphic deletion enabler**
**จำเป็นต้องมี definition** (แม้จะ = default) เพราะ destructor chain จะเรียก base destructor เสมอ