Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> C++

Pure Virtual Functions และ Abstract Classes ใน C++

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

  1. เสมอให้ virtual destructor ใน abstract class
  2. ใช้ override (C++11) ใน derived class
  3. ใช้ final (C++11) ถ้าไม่ต้องการ override ต่อ
  4. Pure virtual destructor ต้องมี definition
  5. 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** อย่างปลอดภัยและมีโครงสร้าง