Virtual function และ Pure virtual function ทั้งคู่ใช้สำหรับ polymorphism แต่มีจุดประสงค์และข้อกำหนดที่แตกต่างกัน
ตารางเปรียบเทียบ
| คุณสมบัติ | Virtual Function | Pure Virtual Function |
|---|---|---|
| Syntax | virtual void foo() { ... } | virtual void foo() = 0; |
| Implementation ใน Base | มี (optional override) | ไม่มี (ต้อง override ใน derived) |
| Class Type | Concrete (สามารถ instantiate ได้) | Abstract (ไม่สามารถ instantiate ได้) |
| Derived Class Obligation | Override ได้ ไม่บังคับ | **ต้อง** override (มิฉะนั้น derived ก็เป็น abstract) |
| Purpose | Default behavior + polymorphism | Define interface/contract |
| V-table Entry | Pointer ไป function body | NULL (หรือ pointer ไป pure virtual thunk) |
ตัวอย่าง Virtual Function (Regular)
#include <iostream>
using namespace std;
class Animal {
public:
virtual void makeSound() { // Virtual with default implementation
cout << "Some generic animal sound\n";
}
virtual ~Animal() = default;
};
class Dog : public Animal {
public:
void makeSound() override {
cout << "Woof!\n";
}
};
class Cat : public Animal {
public:
void makeSound() override {
cout << "Meow!\n";
}
};
// ใช้ base implementation
class SilentAnimal : public Animal {
// ไม่ override makeSound() - ใช้ base version
};
int main() {
Animal* animals[] = {new Dog(), new Cat(), new SilentAnimal()};
for (Animal* a : animals) {
a->makeSound(); // Polymorphic call
}
for (Animal* a : animals) delete a;
return 0;
}
ผลลัพธ์
Woof! Meow! Some generic animal sound
ตัวอย่าง Pure Virtual Function
#include <iostream>
#include <memory>
using namespace std;
class Shape {
public:
// Pure virtual functions = Interface
virtual double area() const = 0;
virtual double perimeter() const = 0;
virtual void draw() const = 0;
// Virtual destructor สำคัญ!
virtual ~Shape() = default;
// Regular method ใช้ pure virtual functions
void printInfo() const {
cout << "Area: " << area() << ", Perimeter: " << perimeter() << endl;
}
};
class Circle : public Shape {
double radius;
public:
Circle(double r) : radius(r) {}
double area() const override { return 3.14159 * radius * radius; }
double perimeter() const override { return 2 * 3.14159 * radius; }
void draw() const override { cout << "Drawing circle (r=" << radius << ")\n"; }
};
class Rectangle : public Shape {
double w, h;
public:
Rectangle(double w_, double h_) : w(w_), h(h_) {}
double area() const override { return w * h; }
double perimeter() const override { return 2 * (w + h); }
void draw() const override { cout << "Drawing rectangle (" << w << "x" << h << ")\n"; }
};
int main() {
// Shape s; // ❌ Error: abstract class
unique_ptr<Shape> shapes[] = {
make_unique<Circle>(5),
make_unique<Rectangle>(4, 6)
};
for (auto& s : shapes) {
s->draw();
s->printInfo();
}
return 0;
}
ผลลัพธ์
Drawing circle (r=5) Area: 78.5397, Perimeter: 31.4159 Drawing rectangle (4x6) Area: 24, Perimeter: 20
Pure Virtual Function ที่มี Definition (Advanced)
Pure virtual function **สามารถมี definition ได้** (ยังคงเป็น pure virtual):
class Base {
public:
virtual void cleanup() = 0; // Pure virtual
};
// Definition แยกต่างหาก (ยังคงเป็น pure virtual)
void Base::cleanup() {
cout << "Base cleanup logic\n";
}
class Derived : public Base {
public:
void cleanup() override {
Base::cleanup(); // เรียก base implementation ได้!
cout << "Derived cleanup\n";
}
};
เมื่อไหร่ควรใช้อะไร?
| สถานการณ์ | แนะนำ |
|---|---|
| มี default behavior ที่สมเหตุสมผล | Regular virtual function |
| ทุก derived class ต้อง implement เอง | Pure virtual function |
| ต้องการสร้าง interface (contract) | Pure virtual functions only |
| Base class ควรไม่ถูก instantiate | Pure virtual (ทำให้เป็น abstract) |
| ต้องการ common implementation + บังคับ override | Pure virtual + provide definition |
Abstract Class Design Guidelines
- **Interface classes**: มีแต่ pure virtual functions + virtual destructor
- **Abstract base classes**: มีทั้ง pure virtual และ regular virtual + data members
- **เสมอ**: virtual destructor (หรือ protected non-virtual destructor)
- **หลีกเลี่ยง**: เรียก virtual functions ใน constructor/destructor
- **ใช้**:
overrideและfinal(C++11)
สรุป
Virtual function = "นี่คือ default behavior แต่อนุญาตให้ override"
Pure virtual function = "นี่คือ contract ที่ derived class ต้อง implement เอง"
ทั้งคู่ร่วมกันสร้าง **Runtime Polymorphism** ใน C++