Pure virtual functions และ Abstract classes เป็นหัวใจของ **Interface-based Programming** และ **Polymorphism** ใน C++
Pure Virtual Function
class Base {
public:
virtual void doSomething() = 0; // Pure virtual
// ^^^^^^ ไม่มี body, ต้อง override ใน derived
};
Abstract Class
คลาสที่มี **pure virtual function อย่างน้อย 1 ตัว** เรียกว่า Abstract Class
คุณสมบัติของ Abstract Class
| คุณสมบัติ | รายละเอียด |
|---|---|
| Instantiate ได้ไหม | ❌ ไม่ได้ (compile error) |
| Pointer/Reference ได้ไหม | ✅ ได้ (ใช้สำหรับ polymorphism) |
| มี regular members ได้ไหม | ✅ ได้ (data, non-virtual functions, constructors) |
| Derived class ต้องทำอะไร | Implement pure virtual functions ทั้งหมด |
| V-table | มี slot สำหรับ pure virtual แต่ไม่มี address (incomplete) |
ตัวอย่างครบถ้วน
#include <iostream>
#include <memory>
#include <vector>
using namespace std;
// Abstract base class (Interface)
class Drawable {
public:
virtual void draw() const = 0; // Pure virtual
virtual double area() const = 0; // Pure virtual
virtual ~Drawable() = default; // Virtual destructor
// Regular member function (มี implementation)
void printInfo() const {
cout << "Area: " << area() << endl;
}
};
// Concrete derived classes
class Circle : public Drawable {
double radius;
public:
Circle(double r) : radius(r) {}
void draw() const override {
cout << "Drawing Circle (r=" << radius << ")" << endl;
}
double area() const override {
return 3.14159 * radius * radius;
}
};
class Rectangle : public Drawable {
double width, height;
public:
Rectangle(double w, double h) : width(w), height(h) {}
void draw() const override {
cout << "Drawing Rectangle (" << width << "x" << height << ")" << endl;
}
double area() const override {
return width * height;
}
};
// ฟังก์ชันที่ทำงานกับ interface (Upcasting)
void renderAll(const vector<unique_ptr<Drawable>>& objects) {
for (const auto& obj : objects) {
obj->draw();
obj->printInfo(); // ใช้ base class method
}
}
int main() {
// Drawable d; // ❌ Error: abstract class
vector<unique_ptr<Drawable>> shapes;
shapes.push_back(make_unique<Circle>(5.0));
shapes.push_back(make_unique<Rectangle>(4.0, 6.0));
shapes.push_back(make_unique<Circle>(3.0));
renderAll(shapes);
return 0;
}
ผลลัพธ์
Drawing Circle (r=5) Area: 78.5397 Drawing Rectangle (4x6) Area: 24 Drawing Circle (r=3) Area: 28.2743
Interface vs Abstract Class ใน C++
C++ ไม่มี keyword interface แต่ใช้ **Abstract Class ที่มีแต่ pure virtual functions** แทน:
// "Interface" ใน C++
class ISerializable {
public:
virtual void serialize(ostream& out) const = 0;
virtual void deserialize(istream& in) = 0;
virtual ~ISerializable() = default;
};
// Abstract class ที่มี implementation บ้าง
class Shape {
public:
virtual double area() const = 0; // Pure
virtual void draw() const = 0; // Pure
virtual void print() const { // Regular (มี body)
cout << "Area: " << area() << endl;
}
virtual ~Shape() = default;
};
Best Practices
- เสมอให้ virtual destructor ใน abstract class
- ใช้
override(C++11) ใน derived class - ใช้
final(C++11) ถ้าไม่ต้องการ override ต่อ - Pure virtual destructor ต้องมี definition
- Protected constructor ใน abstract class (ป้องกัน direct instantiation)
Common Pitfall: เรียก Pure Virtual ใน Constructor
class Base {
public:
Base() { init(); } // ❌ Dangerous!
virtual void init() = 0;
};
class Derived : public Base {
public:
void init() override { /* ... */ }
};
// เรียก Base::init() (pure virtual) -> Undefined Behavior (มัก crash)
สรุป
Abstract class + Pure virtual functions = **Contract/Interface** ที่บังคับ derived classes ให้ implement behavior ที่กำหนด ใช้สำหรับ **Upcasting** และ **Runtime Polymorphism** อย่างปลอดภัยและมีโครงสร้าง